| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #include "Scene/BsTransform.h" |
| 4 | #include "Private/RTTI/BsTransformRTTI.h" |
| 5 | |
| 6 | namespace bs |
| 7 | { |
| 8 | Transform Transform::IDENTITY; |
| 9 | |
| 10 | Transform::Transform(const Vector3& position, const Quaternion& rotation, const Vector3& scale) |
| 11 | : mPosition(position), mRotation(rotation), mScale(scale) |
| 12 | { } |
| 13 | |
| 14 | Matrix4 Transform::getMatrix() const |
| 15 | { |
| 16 | return Matrix4::TRS(mPosition, mRotation, mScale); |
| 17 | } |
| 18 | |
| 19 | Matrix4 Transform::getInvMatrix() const |
| 20 | { |
| 21 | return Matrix4::inverseTRS(mPosition, mRotation, mScale); |
| 22 | } |
| 23 | |
| 24 | void Transform::makeLocal(const Transform& parent) |
| 25 | { |
| 26 | setWorldPosition(mPosition, parent); |
| 27 | setWorldRotation(mRotation, parent); |
| 28 | setWorldScale(mScale, parent); |
| 29 | } |
| 30 | |
| 31 | void Transform::makeWorld(const Transform& parent) |
| 32 | { |
| 33 | // Update orientation |
| 34 | const Quaternion& parentOrientation = parent.getRotation(); |
| 35 | mRotation = parentOrientation * mRotation; |
| 36 | |
| 37 | // Update scale |
| 38 | const Vector3& parentScale = parent.getScale(); |
| 39 | |
| 40 | // Scale own position by parent scale, just combine as equivalent axes, no shearing |
| 41 | mScale = parentScale * mScale; |
| 42 | |
| 43 | // Change position vector based on parent's orientation & scale |
| 44 | mPosition = parentOrientation.rotate(parentScale * mPosition); |
| 45 | |
| 46 | // Add altered position vector to parents |
| 47 | mPosition += parent.getPosition(); |
| 48 | } |
| 49 | |
| 50 | void Transform::setWorldPosition(const Vector3& position, const Transform& parent) |
| 51 | { |
| 52 | Vector3 invScale = parent.getScale(); |
| 53 | if (invScale.x != 0) invScale.x = 1.0f / invScale.x; |
| 54 | if (invScale.y != 0) invScale.y = 1.0f / invScale.y; |
| 55 | if (invScale.z != 0) invScale.z = 1.0f / invScale.z; |
| 56 | |
| 57 | Quaternion invRotation = parent.getRotation().inverse(); |
| 58 | |
| 59 | mPosition = invRotation.rotate(position - parent.getPosition()) * invScale; |
| 60 | } |
| 61 | |
| 62 | void Transform::setWorldRotation(const Quaternion& rotation, const Transform& parent) |
| 63 | { |
| 64 | Quaternion invRotation = parent.getRotation().inverse(); |
| 65 | mRotation = invRotation * rotation; |
| 66 | } |
| 67 | |
| 68 | void Transform::setWorldScale(const Vector3& scale, const Transform& parent) |
| 69 | { |
| 70 | Matrix4 parentMatrix = parent.getMatrix(); |
| 71 | Matrix3 rotScale = parentMatrix.get3x3(); |
| 72 | rotScale = rotScale.inverse(); |
| 73 | |
| 74 | Matrix3 scaleMat = Matrix3(Quaternion::IDENTITY, scale); |
| 75 | scaleMat = rotScale * scaleMat; |
| 76 | |
| 77 | Quaternion rotation; |
| 78 | Vector3 localScale; |
| 79 | scaleMat.decomposition(rotation, localScale); |
| 80 | |
| 81 | mScale = localScale; |
| 82 | } |
| 83 | |
| 84 | void Transform::lookAt(const Vector3& location, const Vector3& up) |
| 85 | { |
| 86 | Vector3 forward = location - getPosition(); |
| 87 | |
| 88 | Quaternion rotation = getRotation(); |
| 89 | rotation.lookRotation(forward, up); |
| 90 | setRotation(rotation); |
| 91 | } |
| 92 | |
| 93 | void Transform::move(const Vector3& vec) |
| 94 | { |
| 95 | setPosition(mPosition + vec); |
| 96 | } |
| 97 | |
| 98 | void Transform::moveRelative(const Vector3& vec) |
| 99 | { |
| 100 | // Transform the axes of the relative vector by camera's local axes |
| 101 | Vector3 trans = mRotation.rotate(vec); |
| 102 | |
| 103 | setPosition(mPosition + trans); |
| 104 | } |
| 105 | |
| 106 | void Transform::rotate(const Vector3& axis, const Radian& angle) |
| 107 | { |
| 108 | Quaternion q; |
| 109 | q.fromAxisAngle(axis, angle); |
| 110 | rotate(q); |
| 111 | } |
| 112 | |
| 113 | void Transform::rotate(const Quaternion& q) |
| 114 | { |
| 115 | // Note the order of the mult, i.e. q comes after |
| 116 | |
| 117 | // Normalize the quat to avoid cumulative problems with precision |
| 118 | Quaternion qnorm = q; |
| 119 | qnorm.normalize(); |
| 120 | setRotation(qnorm * mRotation); |
| 121 | } |
| 122 | |
| 123 | void Transform::roll(const Radian& angle) |
| 124 | { |
| 125 | // Rotate around local Z axis |
| 126 | Vector3 zAxis = mRotation.rotate(Vector3::UNIT_Z); |
| 127 | rotate(zAxis, angle); |
| 128 | } |
| 129 | |
| 130 | void Transform::yaw(const Radian& angle) |
| 131 | { |
| 132 | Vector3 yAxis = mRotation.rotate(Vector3::UNIT_Y); |
| 133 | rotate(yAxis, angle); |
| 134 | } |
| 135 | |
| 136 | void Transform::pitch(const Radian& angle) |
| 137 | { |
| 138 | // Rotate around local X axis |
| 139 | Vector3 xAxis = mRotation.rotate(Vector3::UNIT_X); |
| 140 | rotate(xAxis, angle); |
| 141 | } |
| 142 | |
| 143 | void Transform::setForward(const Vector3& forwardDir) |
| 144 | { |
| 145 | Quaternion currentRotation = getRotation(); |
| 146 | currentRotation.lookRotation(forwardDir); |
| 147 | setRotation(currentRotation); |
| 148 | } |
| 149 | |
| 150 | RTTITypeBase* Transform::getRTTIStatic() |
| 151 | { |
| 152 | return TransformRTTI::instance(); |
| 153 | } |
| 154 | |
| 155 | RTTITypeBase* Transform::getRTTI() const |
| 156 | { |
| 157 | return Transform::getRTTIStatic(); |
| 158 | } |
| 159 | } |
| 160 | |