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 | |
7 | #include "Math/BsVector3.h" |
8 | #include "Math/BsMatrix3.h" |
9 | #include "Math/BsVector4.h" |
10 | #include "Math/BsPlane.h" |
11 | |
12 | namespace bs |
13 | { |
14 | /** @addtogroup Math |
15 | * @{ |
16 | */ |
17 | |
18 | /** Class representing a 4x4 matrix, in row major format. */ |
19 | class BS_UTILITY_EXPORT Matrix4 |
20 | { |
21 | public: |
22 | Matrix4() = default; |
23 | constexpr Matrix4(const Matrix4&) = default; |
24 | constexpr Matrix4& operator=(const Matrix4&) = default; |
25 | |
26 | constexpr Matrix4(BS_ZERO) |
27 | :m{ {0.0f, 0.0f, 0.0f, 0.0f}, |
28 | {0.0f, 0.0f, 0.0f, 0.0f}, |
29 | {0.0f, 0.0f, 0.0f, 0.0f}, |
30 | {0.0f, 0.0f, 0.0f, 0.0f} } |
31 | { } |
32 | |
33 | constexpr Matrix4(BS_IDENTITY) |
34 | :m{ {1.0f, 0.0f, 0.0f, 0.0f}, |
35 | {0.0f, 1.0f, 0.0f, 0.0f}, |
36 | {0.0f, 0.0f, 1.0f, 0.0f}, |
37 | {0.0f, 0.0f, 0.0f, 1.0f} } |
38 | { } |
39 | |
40 | constexpr Matrix4( |
41 | float m00, float m01, float m02, float m03, |
42 | float m10, float m11, float m12, float m13, |
43 | float m20, float m21, float m22, float m23, |
44 | float m30, float m31, float m32, float m33) |
45 | :m{ {m00, m01, m02, m03}, |
46 | {m10, m11, m12, m13}, |
47 | {m20, m21, m22, m23}, |
48 | {m30, m31, m32, m33} } |
49 | { } |
50 | |
51 | /** Creates a 4x4 transformation matrix with a zero translation part from a rotation/scaling 3x3 matrix. */ |
52 | constexpr explicit Matrix4(const Matrix3& mat3) |
53 | :m{ {mat3.m[0][0], mat3.m[0][1], mat3.m[0][2], 0.0f}, |
54 | {mat3.m[1][0], mat3.m[1][1], mat3.m[1][2], 0.0f}, |
55 | {mat3.m[2][0], mat3.m[2][1], mat3.m[2][2], 0.0f}, |
56 | {0.0f, 0.0f, 0.0f, 1.0f} } |
57 | { } |
58 | |
59 | /** Swaps the contents of this matrix with another. */ |
60 | void swap(Matrix4& other) |
61 | { |
62 | std::swap(m[0][0], other.m[0][0]); |
63 | std::swap(m[0][1], other.m[0][1]); |
64 | std::swap(m[0][2], other.m[0][2]); |
65 | std::swap(m[0][3], other.m[0][3]); |
66 | std::swap(m[1][0], other.m[1][0]); |
67 | std::swap(m[1][1], other.m[1][1]); |
68 | std::swap(m[1][2], other.m[1][2]); |
69 | std::swap(m[1][3], other.m[1][3]); |
70 | std::swap(m[2][0], other.m[2][0]); |
71 | std::swap(m[2][1], other.m[2][1]); |
72 | std::swap(m[2][2], other.m[2][2]); |
73 | std::swap(m[2][3], other.m[2][3]); |
74 | std::swap(m[3][0], other.m[3][0]); |
75 | std::swap(m[3][1], other.m[3][1]); |
76 | std::swap(m[3][2], other.m[3][2]); |
77 | std::swap(m[3][3], other.m[3][3]); |
78 | } |
79 | |
80 | /** Returns a row of the matrix. */ |
81 | Vector4& operator[] (UINT32 row) |
82 | { |
83 | assert(row < 4); |
84 | |
85 | return *(Vector4*)m[row]; |
86 | } |
87 | |
88 | /** Returns a row of the matrix. */ |
89 | const Vector4& operator[] (UINT32 row) const |
90 | { |
91 | assert(row < 4); |
92 | |
93 | return *(Vector4*)m[row]; |
94 | } |
95 | |
96 | Matrix4 operator* (const Matrix4 &rhs) const |
97 | { |
98 | Matrix4 r; |
99 | |
100 | r.m[0][0] = m[0][0] * rhs.m[0][0] + m[0][1] * rhs.m[1][0] + m[0][2] * rhs.m[2][0] + m[0][3] * rhs.m[3][0]; |
101 | r.m[0][1] = m[0][0] * rhs.m[0][1] + m[0][1] * rhs.m[1][1] + m[0][2] * rhs.m[2][1] + m[0][3] * rhs.m[3][1]; |
102 | r.m[0][2] = m[0][0] * rhs.m[0][2] + m[0][1] * rhs.m[1][2] + m[0][2] * rhs.m[2][2] + m[0][3] * rhs.m[3][2]; |
103 | r.m[0][3] = m[0][0] * rhs.m[0][3] + m[0][1] * rhs.m[1][3] + m[0][2] * rhs.m[2][3] + m[0][3] * rhs.m[3][3]; |
104 | |
105 | r.m[1][0] = m[1][0] * rhs.m[0][0] + m[1][1] * rhs.m[1][0] + m[1][2] * rhs.m[2][0] + m[1][3] * rhs.m[3][0]; |
106 | r.m[1][1] = m[1][0] * rhs.m[0][1] + m[1][1] * rhs.m[1][1] + m[1][2] * rhs.m[2][1] + m[1][3] * rhs.m[3][1]; |
107 | r.m[1][2] = m[1][0] * rhs.m[0][2] + m[1][1] * rhs.m[1][2] + m[1][2] * rhs.m[2][2] + m[1][3] * rhs.m[3][2]; |
108 | r.m[1][3] = m[1][0] * rhs.m[0][3] + m[1][1] * rhs.m[1][3] + m[1][2] * rhs.m[2][3] + m[1][3] * rhs.m[3][3]; |
109 | |
110 | r.m[2][0] = m[2][0] * rhs.m[0][0] + m[2][1] * rhs.m[1][0] + m[2][2] * rhs.m[2][0] + m[2][3] * rhs.m[3][0]; |
111 | r.m[2][1] = m[2][0] * rhs.m[0][1] + m[2][1] * rhs.m[1][1] + m[2][2] * rhs.m[2][1] + m[2][3] * rhs.m[3][1]; |
112 | r.m[2][2] = m[2][0] * rhs.m[0][2] + m[2][1] * rhs.m[1][2] + m[2][2] * rhs.m[2][2] + m[2][3] * rhs.m[3][2]; |
113 | r.m[2][3] = m[2][0] * rhs.m[0][3] + m[2][1] * rhs.m[1][3] + m[2][2] * rhs.m[2][3] + m[2][3] * rhs.m[3][3]; |
114 | |
115 | r.m[3][0] = m[3][0] * rhs.m[0][0] + m[3][1] * rhs.m[1][0] + m[3][2] * rhs.m[2][0] + m[3][3] * rhs.m[3][0]; |
116 | r.m[3][1] = m[3][0] * rhs.m[0][1] + m[3][1] * rhs.m[1][1] + m[3][2] * rhs.m[2][1] + m[3][3] * rhs.m[3][1]; |
117 | r.m[3][2] = m[3][0] * rhs.m[0][2] + m[3][1] * rhs.m[1][2] + m[3][2] * rhs.m[2][2] + m[3][3] * rhs.m[3][2]; |
118 | r.m[3][3] = m[3][0] * rhs.m[0][3] + m[3][1] * rhs.m[1][3] + m[3][2] * rhs.m[2][3] + m[3][3] * rhs.m[3][3]; |
119 | |
120 | return r; |
121 | } |
122 | |
123 | Matrix4 operator+ (const Matrix4 &rhs) const |
124 | { |
125 | Matrix4 r; |
126 | |
127 | r.m[0][0] = m[0][0] + rhs.m[0][0]; |
128 | r.m[0][1] = m[0][1] + rhs.m[0][1]; |
129 | r.m[0][2] = m[0][2] + rhs.m[0][2]; |
130 | r.m[0][3] = m[0][3] + rhs.m[0][3]; |
131 | |
132 | r.m[1][0] = m[1][0] + rhs.m[1][0]; |
133 | r.m[1][1] = m[1][1] + rhs.m[1][1]; |
134 | r.m[1][2] = m[1][2] + rhs.m[1][2]; |
135 | r.m[1][3] = m[1][3] + rhs.m[1][3]; |
136 | |
137 | r.m[2][0] = m[2][0] + rhs.m[2][0]; |
138 | r.m[2][1] = m[2][1] + rhs.m[2][1]; |
139 | r.m[2][2] = m[2][2] + rhs.m[2][2]; |
140 | r.m[2][3] = m[2][3] + rhs.m[2][3]; |
141 | |
142 | r.m[3][0] = m[3][0] + rhs.m[3][0]; |
143 | r.m[3][1] = m[3][1] + rhs.m[3][1]; |
144 | r.m[3][2] = m[3][2] + rhs.m[3][2]; |
145 | r.m[3][3] = m[3][3] + rhs.m[3][3]; |
146 | |
147 | return r; |
148 | } |
149 | |
150 | Matrix4 operator- (const Matrix4 &rhs) const |
151 | { |
152 | Matrix4 r; |
153 | r.m[0][0] = m[0][0] - rhs.m[0][0]; |
154 | r.m[0][1] = m[0][1] - rhs.m[0][1]; |
155 | r.m[0][2] = m[0][2] - rhs.m[0][2]; |
156 | r.m[0][3] = m[0][3] - rhs.m[0][3]; |
157 | |
158 | r.m[1][0] = m[1][0] - rhs.m[1][0]; |
159 | r.m[1][1] = m[1][1] - rhs.m[1][1]; |
160 | r.m[1][2] = m[1][2] - rhs.m[1][2]; |
161 | r.m[1][3] = m[1][3] - rhs.m[1][3]; |
162 | |
163 | r.m[2][0] = m[2][0] - rhs.m[2][0]; |
164 | r.m[2][1] = m[2][1] - rhs.m[2][1]; |
165 | r.m[2][2] = m[2][2] - rhs.m[2][2]; |
166 | r.m[2][3] = m[2][3] - rhs.m[2][3]; |
167 | |
168 | r.m[3][0] = m[3][0] - rhs.m[3][0]; |
169 | r.m[3][1] = m[3][1] - rhs.m[3][1]; |
170 | r.m[3][2] = m[3][2] - rhs.m[3][2]; |
171 | r.m[3][3] = m[3][3] - rhs.m[3][3]; |
172 | |
173 | return r; |
174 | } |
175 | |
176 | inline bool operator== (const Matrix4& rhs) const |
177 | { |
178 | if (m[0][0] != rhs.m[0][0] || m[0][1] != rhs.m[0][1] || m[0][2] != rhs.m[0][2] || m[0][3] != rhs.m[0][3] || |
179 | m[1][0] != rhs.m[1][0] || m[1][1] != rhs.m[1][1] || m[1][2] != rhs.m[1][2] || m[1][3] != rhs.m[1][3] || |
180 | m[2][0] != rhs.m[2][0] || m[2][1] != rhs.m[2][1] || m[2][2] != rhs.m[2][2] || m[2][3] != rhs.m[2][3] || |
181 | m[3][0] != rhs.m[3][0] || m[3][1] != rhs.m[3][1] || m[3][2] != rhs.m[3][2] || m[3][3] != rhs.m[3][3]) |
182 | { |
183 | return false; |
184 | } |
185 | |
186 | return true; |
187 | } |
188 | |
189 | inline bool operator!= (const Matrix4& rhs) const |
190 | { |
191 | return !operator==(rhs); |
192 | } |
193 | |
194 | Matrix4 operator*(float rhs) const |
195 | { |
196 | return Matrix4(rhs*m[0][0], rhs*m[0][1], rhs*m[0][2], rhs*m[0][3], |
197 | rhs*m[1][0], rhs*m[1][1], rhs*m[1][2], rhs*m[1][3], |
198 | rhs*m[2][0], rhs*m[2][1], rhs*m[2][2], rhs*m[2][3], |
199 | rhs*m[3][0], rhs*m[3][1], rhs*m[3][2], rhs*m[3][3]); |
200 | } |
201 | |
202 | /** Returns the specified column of the matrix, ignoring the last row. */ |
203 | Vector3 getColumn(UINT32 col) const |
204 | { |
205 | assert(col < 4); |
206 | |
207 | return Vector3(m[0][col], m[1][col], m[2][col]); |
208 | } |
209 | |
210 | /** Returns the specified column of the matrix. */ |
211 | Vector4 getColumn4D(UINT32 col) const |
212 | { |
213 | assert(col < 4); |
214 | |
215 | return Vector4(m[0][col], m[1][col], m[2][col], m[3][col]); |
216 | } |
217 | |
218 | /** Returns a transpose of the matrix (switched columns and rows). */ |
219 | Matrix4 transpose() const |
220 | { |
221 | return Matrix4(m[0][0], m[1][0], m[2][0], m[3][0], |
222 | m[0][1], m[1][1], m[2][1], m[3][1], |
223 | m[0][2], m[1][2], m[2][2], m[3][2], |
224 | m[0][3], m[1][3], m[2][3], m[3][3]); |
225 | } |
226 | |
227 | /** Assigns the vector to a column of the matrix. */ |
228 | void setColumn(UINT32 idx, const Vector4& column) |
229 | { |
230 | m[0][idx] = column.x; |
231 | m[1][idx] = column.y; |
232 | m[2][idx] = column.z; |
233 | m[3][idx] = column.w; |
234 | } |
235 | |
236 | /** Assigns the vector to a row of the matrix. */ |
237 | void setRow(UINT32 idx, const Vector4& column) |
238 | { |
239 | m[idx][0] = column.x; |
240 | m[idx][1] = column.y; |
241 | m[idx][2] = column.z; |
242 | m[idx][3] = column.w; |
243 | } |
244 | |
245 | /** Returns the rotation/scaling part of the matrix as a 3x3 matrix. */ |
246 | Matrix3 get3x3() const |
247 | { |
248 | Matrix3 m3x3; |
249 | m3x3.m[0][0] = m[0][0]; |
250 | m3x3.m[0][1] = m[0][1]; |
251 | m3x3.m[0][2] = m[0][2]; |
252 | m3x3.m[1][0] = m[1][0]; |
253 | m3x3.m[1][1] = m[1][1]; |
254 | m3x3.m[1][2] = m[1][2]; |
255 | m3x3.m[2][0] = m[2][0]; |
256 | m3x3.m[2][1] = m[2][1]; |
257 | m3x3.m[2][2] = m[2][2]; |
258 | |
259 | return m3x3; |
260 | } |
261 | |
262 | /** Calculates the adjoint of the matrix. */ |
263 | Matrix4 adjoint() const; |
264 | |
265 | /** Calculates the determinant of the matrix. */ |
266 | float determinant() const; |
267 | |
268 | /** Calculates the determinant of the 3x3 sub-matrix. */ |
269 | float determinant3x3() const; |
270 | |
271 | /** Calculates the inverse of the matrix. */ |
272 | Matrix4 inverse() const; |
273 | |
274 | /** |
275 | * Creates a matrix from translation, rotation and scale. |
276 | * |
277 | * @note The transformation are applied in scale->rotation->translation order. |
278 | */ |
279 | void setTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale); |
280 | |
281 | /** |
282 | * Creates a matrix from inverse translation, rotation and scale. |
283 | * |
284 | * @note This is cheaper than setTRS() and then performing inverse(). |
285 | */ |
286 | void setInverseTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale); |
287 | |
288 | /** |
289 | * Decompose a Matrix4 to translation, rotation and scale. |
290 | * |
291 | * @note |
292 | * This method is unable to decompose all types of matrices, in particular these are the limitations: |
293 | * - Only translation, rotation and scale transforms are supported |
294 | * - Plain TRS matrices (that aren't composed with other matrices) can always be decomposed |
295 | * - Composed TRS matrices can be decomposed ONLY if the scaling factor is uniform |
296 | */ |
297 | void decomposition(Vector3& position, Quaternion& rotation, Vector3& scale) const; |
298 | |
299 | /** Extracts the translation (position) part of the matrix. */ |
300 | Vector3 getTranslation() const { return Vector3(m[0][3], m[1][3], m[2][3]); } |
301 | |
302 | /** |
303 | * Check whether or not the matrix is affine matrix. |
304 | * |
305 | * @note An affine matrix is a 4x4 matrix with row 3 equal to (0, 0, 0, 1), meaning no projective coefficients. |
306 | */ |
307 | bool isAffine() const |
308 | { |
309 | return m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0 && m[3][3] == 1; |
310 | } |
311 | |
312 | /** |
313 | * Returns the inverse of the affine matrix. |
314 | * |
315 | * @note Matrix must be affine. |
316 | */ |
317 | Matrix4 inverseAffine() const; |
318 | |
319 | /** |
320 | * Concatenate two affine matrices. |
321 | * |
322 | * @note Both matrices must be affine. |
323 | */ |
324 | Matrix4 concatenateAffine(const Matrix4 &other) const |
325 | { |
326 | return Matrix4( |
327 | m[0][0] * other.m[0][0] + m[0][1] * other.m[1][0] + m[0][2] * other.m[2][0], |
328 | m[0][0] * other.m[0][1] + m[0][1] * other.m[1][1] + m[0][2] * other.m[2][1], |
329 | m[0][0] * other.m[0][2] + m[0][1] * other.m[1][2] + m[0][2] * other.m[2][2], |
330 | m[0][0] * other.m[0][3] + m[0][1] * other.m[1][3] + m[0][2] * other.m[2][3] + m[0][3], |
331 | |
332 | m[1][0] * other.m[0][0] + m[1][1] * other.m[1][0] + m[1][2] * other.m[2][0], |
333 | m[1][0] * other.m[0][1] + m[1][1] * other.m[1][1] + m[1][2] * other.m[2][1], |
334 | m[1][0] * other.m[0][2] + m[1][1] * other.m[1][2] + m[1][2] * other.m[2][2], |
335 | m[1][0] * other.m[0][3] + m[1][1] * other.m[1][3] + m[1][2] * other.m[2][3] + m[1][3], |
336 | |
337 | m[2][0] * other.m[0][0] + m[2][1] * other.m[1][0] + m[2][2] * other.m[2][0], |
338 | m[2][0] * other.m[0][1] + m[2][1] * other.m[1][1] + m[2][2] * other.m[2][1], |
339 | m[2][0] * other.m[0][2] + m[2][1] * other.m[1][2] + m[2][2] * other.m[2][2], |
340 | m[2][0] * other.m[0][3] + m[2][1] * other.m[1][3] + m[2][2] * other.m[2][3] + m[2][3], |
341 | |
342 | 0, 0, 0, 1); |
343 | } |
344 | |
345 | /** |
346 | * Transform a plane by this matrix. |
347 | * |
348 | * @note Matrix must be affine. |
349 | */ |
350 | Plane multiplyAffine(const Plane& p) const |
351 | { |
352 | Vector4 localNormal(p.normal.x, p.normal.y, p.normal.z, 0.0f); |
353 | Vector4 localPoint = localNormal * p.d; |
354 | localPoint.w = 1.0f; |
355 | |
356 | Matrix4 itMat = inverse().transpose(); |
357 | Vector4 worldNormal = itMat.multiplyAffine(localNormal); |
358 | Vector4 worldPoint = multiplyAffine(localPoint); |
359 | |
360 | float d = worldNormal.dot(worldPoint); |
361 | |
362 | return Plane(worldNormal.x, worldNormal.y, worldNormal.z, d); |
363 | } |
364 | |
365 | /** |
366 | * Transform a 3D point by this matrix. |
367 | * |
368 | * @note Matrix must be affine, if it is not use multiply() method. |
369 | */ |
370 | Vector3 multiplyAffine(const Vector3& v) const |
371 | { |
372 | return Vector3( |
373 | m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3], |
374 | m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3], |
375 | m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]); |
376 | } |
377 | |
378 | /** |
379 | * Transform a 4D vector by this matrix. |
380 | * |
381 | * @note Matrix must be affine, if it is not use multiply() method. |
382 | */ |
383 | Vector4 multiplyAffine(const Vector4& v) const |
384 | { |
385 | return Vector4( |
386 | m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w, |
387 | m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w, |
388 | m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w, |
389 | v.w); |
390 | } |
391 | |
392 | /** Transform a 3D direction by this matrix. */ |
393 | Vector3 multiplyDirection(const Vector3& v) const |
394 | { |
395 | return Vector3( |
396 | m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, |
397 | m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z, |
398 | m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z); |
399 | } |
400 | |
401 | /** |
402 | * Transform a 3D point by this matrix. |
403 | * |
404 | * @note |
405 | * w component of the vector is assumed to be 1. After transformation all components |
406 | * are projected back so that w remains 1. |
407 | * @note |
408 | * If your matrix doesn't contain projection components use multiplyAffine() method as it is faster. |
409 | */ |
410 | Vector3 multiply(const Vector3& v) const |
411 | { |
412 | Vector3 r(BsZero); |
413 | |
414 | float fInvW = 1.0f / (m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3]); |
415 | |
416 | r.x = (m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3]) * fInvW; |
417 | r.y = (m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3]) * fInvW; |
418 | r.z = (m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]) * fInvW; |
419 | |
420 | return r; |
421 | } |
422 | |
423 | /** |
424 | * Transform a 4D vector by this matrix. |
425 | * |
426 | * @note If your matrix doesn't contain projection components use multiplyAffine() method as it is faster. |
427 | */ |
428 | Vector4 multiply(const Vector4& v) const |
429 | { |
430 | return Vector4( |
431 | m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w, |
432 | m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w, |
433 | m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w, |
434 | m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w |
435 | ); |
436 | } |
437 | |
438 | /** Creates a view matrix and applies optional reflection. */ |
439 | void makeView(const Vector3& position, const Quaternion& orientation); |
440 | |
441 | /** |
442 | * Creates an ortographic projection matrix that scales the part of the view bounded by @p left, @p right, |
443 | * @p top and @p bottom into [-1, 1] range. If @p far is non-zero the matrix will also transform the depth into |
444 | * [-1, 1] range, otherwise it will leave it as-is. |
445 | */ |
446 | void makeProjectionOrtho(float left, float right, float top, float bottom, float near, float far); |
447 | |
448 | /** Creates a 4x4 transformation matrix that performs translation. */ |
449 | static Matrix4 translation(const Vector3& translation); |
450 | |
451 | /** Creates a 4x4 transformation matrix that performs scaling. */ |
452 | static Matrix4 scaling(const Vector3& scale); |
453 | |
454 | /** Creates a 4x4 transformation matrix that performs uniform scaling. */ |
455 | static Matrix4 scaling(float scale); |
456 | |
457 | /** Creates a 4x4 transformation matrix that performs rotation. */ |
458 | static Matrix4 rotation(const Quaternion& rotation); |
459 | |
460 | /** |
461 | * Creates a 4x4 perspective projection matrix. |
462 | * |
463 | * @param[in] horzFOV Horizontal field of view. |
464 | * @param[in] aspect Aspect ratio. Determines the vertical field of view. |
465 | * @param[in] near Distance to the near plane. |
466 | * @param[in] far Distance to the far plane. |
467 | * @param[in] positiveZ If true the matrix will project geometry as if its looking along the positive Z axis. |
468 | * Otherwise it projects along the negative Z axis (default). |
469 | */ |
470 | static Matrix4 projectionPerspective(const Degree& horzFOV, float aspect, float near, float far, |
471 | bool positiveZ = false); |
472 | |
473 | /** @copydoc makeProjectionOrtho() */ |
474 | static Matrix4 projectionOrthographic(float left, float right, float top, float bottom, float near, float far); |
475 | |
476 | /** Creates a view matrix. */ |
477 | static Matrix4 view(const Vector3& position, const Quaternion& orientation); |
478 | |
479 | /** |
480 | * Creates a matrix from translation, rotation and scale. |
481 | * |
482 | * @note The transformation are applied in scale->rotation->translation order. |
483 | */ |
484 | static Matrix4 TRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale); |
485 | |
486 | /** |
487 | * Creates a matrix from inverse translation, rotation and scale. |
488 | * |
489 | * @note This is cheaper than setTRS() and then performing inverse(). |
490 | */ |
491 | static Matrix4 inverseTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale); |
492 | |
493 | static const Matrix4 ZERO; |
494 | static const Matrix4 IDENTITY; |
495 | |
496 | private: |
497 | float m[4][4]; |
498 | }; |
499 | |
500 | /** @} */ |
501 | |
502 | /** @cond SPECIALIZATIONS */ |
503 | BS_ALLOW_MEMCPY_SERIALIZATION(Matrix4); |
504 | /** @endcond */ |
505 | } |
506 | |