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 | #pragma once |
4 | |
5 | #include "Prerequisites/BsPrerequisitesUtil.h" |
6 | #include "Math/BsVector3.h" |
7 | |
8 | namespace bs |
9 | { |
10 | /** @addtogroup Math |
11 | * @{ |
12 | */ |
13 | |
14 | /** |
15 | * A 3x3 matrix. Can be used for non-homogenous transformations of three dimensional vectors and points. In row major |
16 | * format. |
17 | */ |
18 | class BS_UTILITY_EXPORT Matrix3 |
19 | { |
20 | private: |
21 | struct EulerAngleOrderData |
22 | { |
23 | int a, b, c; |
24 | float sign; |
25 | }; |
26 | |
27 | public: |
28 | Matrix3() = default; |
29 | constexpr Matrix3(const Matrix3&) = default; |
30 | constexpr Matrix3& operator=(const Matrix3&) = default; |
31 | |
32 | constexpr Matrix3(BS_ZERO) |
33 | :m{ { 0.0f, 0.0f, 0.0f}, |
34 | { 0.0f, 0.0f, 0.0f}, |
35 | { 0.0f, 0.0f, 0.0f} } |
36 | { } |
37 | |
38 | constexpr Matrix3(BS_IDENTITY) |
39 | :m{ {1.0f, 0.0f, 0.0f}, |
40 | {0.0f, 1.0f, 0.0f}, |
41 | {0.0f, 0.0f, 1.0f} } |
42 | { } |
43 | |
44 | constexpr Matrix3(float m00, float m01, float m02, |
45 | float m10, float m11, float m12, |
46 | float m20, float m21, float m22) |
47 | :m{{m00, m01, m02}, {m10, m11, m12}, {m20, m21, m22}} |
48 | { } |
49 | |
50 | /** Construct a matrix from a quaternion. */ |
51 | explicit Matrix3(const Quaternion& rotation) |
52 | { |
53 | fromQuaternion(rotation); |
54 | } |
55 | |
56 | /** Construct a matrix that performs rotation and scale. */ |
57 | explicit Matrix3(const Quaternion& rotation, const Vector3& scale) |
58 | { |
59 | fromQuaternion(rotation); |
60 | |
61 | for (int row = 0; row < 3; row++) |
62 | { |
63 | for (int col = 0; col < 3; col++) |
64 | m[row][col] = scale[row]*m[row][col]; |
65 | } |
66 | } |
67 | |
68 | /** Construct a matrix from an angle/axis pair. */ |
69 | explicit Matrix3(const Vector3& axis, const Radian& angle) |
70 | { |
71 | fromAxisAngle(axis, angle); |
72 | } |
73 | |
74 | /** Construct a matrix from 3 orthonormal local axes. */ |
75 | explicit Matrix3(const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis) |
76 | { |
77 | fromAxes(xaxis, yaxis, zaxis); |
78 | } |
79 | |
80 | /** |
81 | * Construct a matrix from euler angles, YXZ ordering. |
82 | * |
83 | * @see Matrix3::fromEulerAngles |
84 | */ |
85 | explicit Matrix3(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle) |
86 | { |
87 | fromEulerAngles(xAngle, yAngle, zAngle); |
88 | } |
89 | |
90 | /** |
91 | * Construct a matrix from euler angles, custom ordering. |
92 | * |
93 | * @see Matrix3::fromEulerAngles |
94 | */ |
95 | explicit Matrix3(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order) |
96 | { |
97 | fromEulerAngles(xAngle, yAngle, zAngle, order); |
98 | } |
99 | |
100 | /** Swaps the contents of this matrix with another. */ |
101 | void swap(Matrix3& other) |
102 | { |
103 | std::swap(m[0][0], other.m[0][0]); |
104 | std::swap(m[0][1], other.m[0][1]); |
105 | std::swap(m[0][2], other.m[0][2]); |
106 | std::swap(m[1][0], other.m[1][0]); |
107 | std::swap(m[1][1], other.m[1][1]); |
108 | std::swap(m[1][2], other.m[1][2]); |
109 | std::swap(m[2][0], other.m[2][0]); |
110 | std::swap(m[2][1], other.m[2][1]); |
111 | std::swap(m[2][2], other.m[2][2]); |
112 | } |
113 | |
114 | /** Returns a row of the matrix. */ |
115 | float* operator[] (UINT32 row) const |
116 | { |
117 | assert(row < 3); |
118 | |
119 | return (float*)m[row]; |
120 | } |
121 | |
122 | Vector3 getColumn(UINT32 col) const; |
123 | void setColumn(UINT32 col, const Vector3& vec); |
124 | |
125 | bool operator== (const Matrix3& rhs) const; |
126 | bool operator!= (const Matrix3& rhs) const; |
127 | |
128 | Matrix3 operator+ (const Matrix3& rhs) const; |
129 | Matrix3 operator- (const Matrix3& rhs) const; |
130 | Matrix3 operator* (const Matrix3& rhs) const; |
131 | Matrix3 operator- () const; |
132 | Matrix3 operator* (float rhs) const; |
133 | |
134 | friend Matrix3 operator* (float lhs, const Matrix3& rhs); |
135 | |
136 | /** Transforms the given vector by this matrix and returns the newly transformed vector. */ |
137 | Vector3 multiply(const Vector3& vec) const; |
138 | |
139 | /** Returns a transpose of the matrix (switched columns and rows). */ |
140 | Matrix3 transpose () const; |
141 | |
142 | /** |
143 | * Calculates an inverse of the matrix if it exists. |
144 | * |
145 | * @param[out] mat Resulting matrix inverse. |
146 | * @param[in] fTolerance (optional) Tolerance to use when checking if determinant is zero (or near zero in this case). |
147 | * Zero determinant means inverse doesn't exist. |
148 | * @return True if inverse exists, false otherwise. |
149 | */ |
150 | bool inverse(Matrix3& mat, float fTolerance = 1e-06f) const; |
151 | |
152 | /** |
153 | * Calculates an inverse of the matrix if it exists. |
154 | * |
155 | * @param[in] fTolerance (optional) Tolerance to use when checking if determinant is zero (or near zero in this case). |
156 | * Zero determinant means inverse doesn't exist. |
157 | * |
158 | * @return Resulting matrix inverse if it exists, otherwise a zero matrix. |
159 | */ |
160 | Matrix3 inverse(float fTolerance = 1e-06f) const; |
161 | |
162 | /** Calculates the matrix determinant. */ |
163 | float determinant() const; |
164 | |
165 | /** |
166 | * Decompose a Matrix3 to rotation and scale. |
167 | * |
168 | * @note |
169 | * Matrix must consist only of rotation and uniform scale transformations, otherwise accurate results are not |
170 | * guaranteed. Applying non-uniform scale guarantees rotation portion will not be accurate. |
171 | */ |
172 | void decomposition(Quaternion& rotation, Vector3& scale) const; |
173 | |
174 | /** |
175 | * Decomposes the matrix into various useful values. |
176 | * |
177 | * @param[out] matL Unitary matrix. Columns form orthonormal bases. If your matrix is affine and |
178 | * doesn't use non-uniform scaling this matrix will be a conjugate transpose of the rotation part of the matrix. |
179 | * @param[out] matS Singular values of the matrix. If your matrix is affine these will be scaling factors of the matrix. |
180 | * @param[out] matR Unitary matrix. Columns form orthonormal bases. If your matrix is affine and |
181 | * doesn't use non-uniform scaling this matrix will be the rotation part of the matrix. |
182 | */ |
183 | void singularValueDecomposition(Matrix3& matL, Vector3& matS, Matrix3& matR) const; |
184 | |
185 | /** |
186 | * Decomposes the matrix into a set of values. |
187 | * |
188 | * @param[out] matQ Columns form orthonormal bases. If your matrix is affine and |
189 | * doesn't use non-uniform scaling this matrix will be the rotation part of the matrix. |
190 | * @param[out] vecD If the matrix is affine these will be scaling factors of the matrix. |
191 | * @param[out] vecU If the matrix is affine these will be shear factors of the matrix. |
192 | */ |
193 | void QDUDecomposition(Matrix3& matQ, Vector3& vecD, Vector3& vecU) const; |
194 | |
195 | /** Gram-Schmidt orthonormalization (applied to columns of rotation matrix) */ |
196 | void orthonormalize(); |
197 | |
198 | /** |
199 | * Converts an orthonormal matrix to axis angle representation. |
200 | * |
201 | * @note Matrix must be orthonormal. |
202 | */ |
203 | void toAxisAngle(Vector3& axis, Radian& angle) const; |
204 | |
205 | /** Creates a rotation matrix from an axis angle representation. */ |
206 | void fromAxisAngle(const Vector3& axis, const Radian& angle); |
207 | |
208 | /** |
209 | * Converts an orthonormal matrix to quaternion representation. |
210 | * |
211 | * @note Matrix must be orthonormal. |
212 | */ |
213 | void toQuaternion(Quaternion& quat) const; |
214 | |
215 | /** Creates a rotation matrix from a quaternion representation. */ |
216 | void fromQuaternion(const Quaternion& quat); |
217 | |
218 | /** Creates a matrix from a three axes. */ |
219 | void fromAxes(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis); |
220 | |
221 | /** |
222 | * Converts an orthonormal matrix to euler angle (pitch/yaw/roll) representation. |
223 | * |
224 | * @param[in,out] xAngle Rotation about x axis. (AKA Pitch) |
225 | * @param[in,out] yAngle Rotation about y axis. (AKA Yaw) |
226 | * @param[in,out] zAngle Rotation about z axis. (AKA Roll) |
227 | * @return True if unique solution was found, false otherwise. |
228 | * |
229 | * @note Matrix must be orthonormal. |
230 | */ |
231 | bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const; |
232 | |
233 | /** |
234 | * Creates a rotation matrix from the provided Pitch/Yaw/Roll angles. |
235 | * |
236 | * @param[in] xAngle Rotation about x axis. (AKA Pitch) |
237 | * @param[in] yAngle Rotation about y axis. (AKA Yaw) |
238 | * @param[in] zAngle Rotation about z axis. (AKA Roll) |
239 | * |
240 | * @note Matrix must be orthonormal. |
241 | * Since different values will be produced depending in which order are the rotations applied, this method assumes |
242 | * they are applied in YXZ order. If you need a specific order, use the overloaded "fromEulerAngles" method instead. |
243 | */ |
244 | void fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle); |
245 | |
246 | /** |
247 | * Creates a rotation matrix from the provided Pitch/Yaw/Roll angles. |
248 | * |
249 | * @param[in] xAngle Rotation about x axis. (AKA Pitch) |
250 | * @param[in] yAngle Rotation about y axis. (AKA Yaw) |
251 | * @param[in] zAngle Rotation about z axis. (AKA Roll) |
252 | * @param[in] order The order in which rotations will be applied. |
253 | * Different rotations can be created depending on the order. |
254 | * |
255 | * @note Matrix must be orthonormal. |
256 | */ |
257 | void fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order); |
258 | |
259 | /** |
260 | * Eigensolver, matrix must be symmetric. |
261 | * |
262 | * @note |
263 | * Eigenvectors are vectors which when transformed by the matrix, only change in magnitude, but not in direction. |
264 | * Eigenvalue is that magnitude. In other words you will get the same result whether you multiply the vector by the |
265 | * matrix or by its eigenvalue. |
266 | */ |
267 | void eigenSolveSymmetric(float eigenValues[3], Vector3 eigenVectors[3]) const; |
268 | |
269 | static constexpr const float EPSILON = 1e-06f; |
270 | static const Matrix3 ZERO; |
271 | static const Matrix3 IDENTITY; |
272 | |
273 | protected: |
274 | friend class Matrix4; |
275 | |
276 | // Support for eigensolver |
277 | void tridiagonal (float diag[3], float subDiag[3]); |
278 | bool QLAlgorithm (float diag[3], float subDiag[3]); |
279 | |
280 | // Support for singular value decomposition |
281 | static constexpr const float SVD_EPSILON = 1e-04f;; |
282 | static constexpr const unsigned int SVD_MAX_ITERS = 32; |
283 | static void bidiagonalize (Matrix3& matA, Matrix3& matL, Matrix3& matR); |
284 | static void golubKahanStep (Matrix3& matA, Matrix3& matL, Matrix3& matR); |
285 | |
286 | float m[3][3]; |
287 | }; |
288 | |
289 | /** @} */ |
290 | |
291 | /** @cond SPECIALIZATIONS */ |
292 | BS_ALLOW_MEMCPY_SERIALIZATION(Matrix3); |
293 | /** @endcond */ |
294 | } |
295 | |