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 | |