godot.core.math.Transform3D.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of godot-library-debug Show documentation
Show all versions of godot-library-debug Show documentation
Contains godot api as kotlin classes and jvm cpp interaction code.
@file:Suppress("PackageDirectoryMismatch", "unused")
package godot.core
import godot.annotation.CoreTypeHelper
import godot.annotation.CoreTypeLocalCopy
import godot.util.RealT
import kotlincompile.definitions.GodotJvmBuildConfig
class Transform3D(
p_basis: Basis,
p_origin: Vector3 = Vector3()
) : CoreType {
@PublishedApi
internal var _basis = Basis(p_basis)
@PublishedApi
internal var _origin = Vector3(p_origin)
//PROPERTIES
/** Return a copy of the basis Basis.
* Warning: Writing basis.x = 2 will only modify a copy, not the actual object.
* To modify it, use basis().
* */
@CoreTypeLocalCopy
var basis
get() = Basis(_basis)
set(value) {
_basis = Basis(value)
}
@CoreTypeHelper
inline fun basis(block: Basis.() -> T): T {
return _basis.block()
}
/** Return a copy of the origin Vector3
* Warning: Writing origin.x = 2 will only modify a copy, not the actual object.
* To modify it, use origin().
* */
@CoreTypeLocalCopy
var origin
get() = Vector3(_origin)
set(value) {
_origin = Vector3(value)
}
@CoreTypeHelper
inline fun origin(block: Vector3.() -> T): T {
return _origin.block()
}
//CONSTANTS
companion object {
inline val IDENTITY: Transform3D
get() = Transform3D(Basis(1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3(0, 0, 0))
inline val FLIP_X: Transform3D
get() = Transform3D(Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3(0, 0, 0))
inline val FLIP_Y: Transform3D
get() = Transform3D(Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3(0, 0, 0))
inline val FLIP_Z: Transform3D
get() = Transform3D(Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3(0, 0, 0))
}
//CONSTRUCTOR
constructor() :
this(Basis(), Vector3(0, 0, 0))
constructor(other: Transform3D) :
this(other._basis, other._origin)
constructor(
xx: Number,
xy: Number,
xz: Number,
yx: Number,
yy: Number,
yz: Number,
zx: Number,
zy: Number,
zz: Number,
tx: Number,
ty: Number,
tz: Number
) :
this(Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz), Vector3(tx, ty, tz))
constructor(from: Quaternion) :
this(Basis(from))
//API
/**
* Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
*/
fun affineInverse(): Transform3D {
val ret = Transform3D(this._basis, this._origin)
ret.affineInvert()
return ret
}
internal fun affineInvert() {
_basis.invert()
_origin = _basis.xform(-_origin)
}
/**
* Interpolates the transform to other Transform by weight amount (0-1).
*/
fun interpolateWith(transform3D: Transform3D, c: RealT): Transform3D {
val srcScale = _basis.getScale()
val srcRot = Quaternion(_basis)
val srcLoc = _origin
val dstScale = transform3D._basis.getScale()
val dstRot = Quaternion(transform3D._basis)
val dstLoc = transform3D._origin
val dst = Transform3D()
dst._basis = Basis(srcRot.slerp(dstRot, c))
dst._basis.scale(srcScale.lerp(dstScale, c))
dst._origin = srcLoc.lerp(dstLoc, c)
return dst
}
/**
* Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling).
*/
fun inverse(): Transform3D {
val ret = Transform3D(this._basis, this._origin)
ret.invert()
return ret
}
internal fun invert() {
_basis.transpose()
_origin = _basis.xform(-_origin)
}
/**
* Returns true if this transform and transform are approximately equal, by calling is_equal_approx on each component.
*/
fun isEqualApprox(transform3D: Transform3D): Boolean {
return transform3D._basis.isEqualApprox(this._basis) && transform3D._origin.isEqualApprox(this._origin)
}
/**
* Returns true if this transform is finite, by calling @GlobalScope.is_finite on each component.
*/
fun isFinite() = basis.isFinite() && origin.isFinite()
/**
* Returns a copy of the transform rotated such that the forward axis (-Z) points towards the [target] position.
* The up axis (+Y) points as close to the [up] vector as possible while staying perpendicular to the forward axis. The resulting transform is orthonormalized. The existing rotation, scale, and skew information from the original transform is discarded. The [target] and [up] vectors cannot be zero, cannot be parallel to each other, and are defined in global/parent space.
* If [useModelFront] is true, the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right).
*/
fun lookingAt(target: Vector3, up: Vector3 = Vector3(0, 1, 0), useModelFront: Boolean = false): Transform3D {
val t = Transform3D(this._basis, this._origin)
t.setLookAt(_origin, target, up, useModelFront)
return t
}
internal fun setLookAt(eye: Vector3, target: Vector3, up: Vector3, useModelFront: Boolean) {
if (GodotJvmBuildConfig.DEBUG) {
require(!eye.isEqualApprox(target)) {
"The eye and target vectors can't be equal."
}
}
_basis = Basis.lookingAt(target - eye, up, useModelFront);
_origin = Vector3(eye)
}
/**
* Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors.
*/
fun orthonormalized(): Transform3D {
val t = Transform3D(this._basis, this._origin)
t.orthonormalize()
return t
}
internal fun orthonormalize() {
_basis.orthonormalize()
}
internal fun rotate(axis: Vector3, phi: RealT) {
val t = rotated(axis, phi)
this._basis = t._basis
this._origin = t._origin
}
/**
* Returns a copy of the transform rotated around the given axis by the given angle (in radians).
* The axis must be a normalized vector.
* This method is an optimized version of multiplying the given transform X with a corresponding rotation transform R from the left, i.e., R * X.
* This can be seen as transforming with respect to the global/parent frame.
*/
fun rotated(axis: Vector3, angle: RealT): Transform3D {
val basis = Basis(axis, angle)
return Transform3D(basis * _basis, basis.xform(_origin))
}
/**
* Returns a copy of the transform rotated around the given axis by the given angle (in radians).
* The axis must be a normalized vector.
* This method is an optimized version of multiplying the given transform X with a corresponding rotation transform R from the right, i.e., X * R.
* This can be seen as transforming with respect to the local frame.
*/
fun rotatedLocal(axis: Vector3, angle: RealT): Transform3D {
val basis = Basis(axis, angle)
return Transform3D(_basis * basis, _origin)
}
internal fun scale(scale: Vector3) {
_basis.scale(scale)
_origin *= scale
}
/**
* Returns a copy of the transform scaled by the given scale factor.
*
* This method is an optimized version of multiplying the given transform X with a corresponding scaling transform S from the left, i.e., S * X.
*
* This can be seen as transforming with respect to the global/parent frame.
*/
fun scaled(scale: Vector3): Transform3D {
return Transform3D(this._basis.scaled(scale), this._origin * scale)
}
/**
* Returns a copy of the transform scaled by the given scale factor.
* This method is an optimized version of multiplying the given transform X with a corresponding scaling transform S from the right, i.e., X * S.
* This can be seen as transforming with respect to the local frame.
*/
fun scaledLocal(scale: Vector3): Transform3D {
return Transform3D(this._basis.scaledLocal(scale), this._origin);
}
internal fun translate(translation: Vector3) {
_origin.x += _basis._x.dot(translation)
_origin.y += _basis._y.dot(translation)
_origin.z += _basis._z.dot(translation)
}
/**
* Returns a copy of the transform translated by the given offset.
* This method is an optimized version of multiplying the given transform X with a corresponding translation transform T from the left, i.e., T * X.
* This can be seen as transforming with respect to the global/parent frame.
*/
fun translated(translation: Vector3): Transform3D {
return Transform3D(this._basis, this._origin + translation);
}
/**
* Returns a copy of the transform translated by the given offset.
* This method is an optimized version of multiplying the given transform X with a corresponding translation transform T from the right, i.e., X * T.
* This can be seen as transforming with respect to the local frame.
*/
fun translatedLocal(translation: Vector3): Transform3D {
return Transform3D(this._basis, this._origin + this._basis.xform(translation));
}
/**
* Transforms the given Vector3 by this transform.
*/
fun xform(vector: Vector3): Vector3 =
Vector3(
_basis._x.dot(vector) + _origin.x,
_basis._y.dot(vector) + _origin.y,
_basis._z.dot(vector) + _origin.z
)
/**
* Transforms the given AABB by this transform.
*/
fun xform(aabb: AABB): AABB {
val x = _basis._x * aabb._size.x
val y = _basis._y * aabb._size.y
val z = _basis._z * aabb._size.z
val pos = xform(aabb._position)
val newAabb = AABB()
newAabb._position = pos
newAabb.expandTo(pos + x)
newAabb.expandTo(pos + y)
newAabb.expandTo(pos + z)
newAabb.expandTo(pos + x + y)
newAabb.expandTo(pos + x + z)
newAabb.expandTo(pos + y + z)
newAabb.expandTo(pos + x + y + z)
return newAabb
}
/**
* Transforms the given Plane by this transform.
*/
fun xform(plane: Plane): Plane {
var point = plane._normal * plane.d
var pointDir = point + plane._normal
point = xform(point)
pointDir = xform(pointDir)
val normal = pointDir - point
normal.normalize()
return Plane(normal, normal.dot(point))
}
/**
* Inverse-transforms the given Vector3 by this transform.
*/
fun xformInv(vector: Vector3): Vector3 {
val v = vector - _origin
return Vector3(
(_basis._x.x * v.x) + (_basis._y.x * v.y) + (_basis._z.x * v.z),
(_basis._x.y * v.x) + (_basis._y.y * v.y) + (_basis._z.y * v.z),
(_basis._x.z * v.x) + (_basis._y.z * v.y) + (_basis._z.z * v.z)
)
}
/**
* Inverse-transforms the given Plane by this transform.
*/
fun xformInv(plane: Plane): Plane {
var point = plane._normal * plane.d
var pointDir = point + plane._normal
point = xformInv(point)
pointDir = xformInv(pointDir)
val normal = pointDir - point
normal.normalize()
return Plane(normal, normal.dot(point))
}
/**
* Inverse-transforms the given AABB by this transform.
*/
fun xformInv(aabb: AABB): AABB {
val vertices = arrayOf(
Vector3(aabb._position.x + aabb._size.x, aabb._position.y + aabb._size.y, aabb._position.z + aabb._size.z),
Vector3(aabb._position.x + aabb._size.x, aabb._position.y + aabb._size.y, aabb._position.z),
Vector3(aabb._position.x + aabb._size.x, aabb._position.y, aabb._position.z + aabb._size.z),
Vector3(aabb._position.x + aabb._size.x, aabb._position.y, aabb._position.z),
Vector3(aabb._position.x, aabb._position.y + aabb._size.y, aabb._position.z + aabb._size.z),
Vector3(aabb._position.x, aabb._position.y + aabb._size.y, aabb._position.z),
Vector3(aabb._position.x, aabb._position.y, aabb._position.z + aabb._size.z),
Vector3(aabb._position.x, aabb._position.y, aabb._position.z)
)
val ret = AABB()
ret._position = xformInv(vertices[0])
for (i in 1..7)
ret.expandTo(xformInv(vertices[i]))
return ret
}
operator fun times(transform3D: Transform3D): Transform3D {
val t = this
t._origin = xform(transform3D._origin)
t._basis *= transform3D._basis
return t
}
override fun equals(other: Any?): Boolean = when (other) {
is Transform3D -> _basis == other._basis && _origin == other._origin
else -> false
}
override fun toString(): String {
return "$_basis - $_origin"
}
override fun hashCode(): Int {
var result = _basis.hashCode()
result = 31 * result + _origin.hashCode()
return result
}
/*
* GDScript related members
*/
constructor(x: Vector3, y: Vector3, z: Vector3, origin: Vector3) :
this(Basis(x, y, z), origin)
}