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