| Flutter Impeller |

matrix.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef FLUTTER_IMPELLER_GEOMETRY_MATRIX_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_MATRIX_H_
7
8 #include <cmath>
9 #include <iomanip>
10 #include <limits>
11 #include <optional>
12 #include <ostream>
13 #include <utility>
14
15 #include "impeller/geometry/matrix_decomposition.h"
16 #include "impeller/geometry/point.h"
17 #include "impeller/geometry/quaternion.h"
18 #include "impeller/geometry/scalar.h"
19 #include "impeller/geometry/shear.h"
20 #include "impeller/geometry/size.h"
21 #include "impeller/geometry/vector.h"
22
23 namespace impeller {
24
25 //------------------------------------------------------------------------------
26 /// @brief A 4x4 matrix using column-major storage.
27 ///
28 /// Utility methods that need to make assumptions about normalized
29 /// device coordinates must use the following convention:
30 /// * Left-handed coordinate system. Positive rotation is
31 /// clockwise about axis of rotation.
32 /// * Lower left corner is -1.0f, -1.0.
33 /// * Upper right corner is 1.0f, 1.0.
34 /// * Visible z-space is from 0.0 to 1.0.
35 /// * This is NOT the same as OpenGL! Be careful.
36 /// * NDC origin is at (0.0f, 0.0f, 0.5f).
37 struct Matrix {
38 union {
39 Scalar m[16];
40 Scalar e[4][4];
41 Vector4 vec[4];
42 };
43
44 //----------------------------------------------------------------------------
45 /// Constructs a default identity matrix.
46 ///
47 constexpr Matrix()
48 // clang-format off
49 : vec{ Vector4(1.0f, 0.0f, 0.0f, 0.0f),
50 Vector4(0.0f, 1.0f, 0.0f, 0.0f),
51 Vector4(0.0f, 0.0f, 1.0f, 0.0f),
52 Vector4(0.0f, 0.0f, 0.0f, 1.0f)} {}
53 // clang-format on
54
55 // clang-format off
56 constexpr Matrix(Scalar m0, Scalar m1, Scalar m2, Scalar m3,
57 Scalar m4, Scalar m5, Scalar m6, Scalar m7,
58 Scalar m8, Scalar m9, Scalar m10, Scalar m11,
59 Scalar m12, Scalar m13, Scalar m14, Scalar m15)
60 : vec{Vector4(m0, m1, m2, m3),
61 Vector4(m4, m5, m6, m7),
62 Vector4(m8, m9, m10, m11),
63 Vector4(m12, m13, m14, m15)} {}
64 // clang-format on
65
66 explicit Matrix(const MatrixDecomposition& decomposition);
67
68 // clang-format off
69 static constexpr Matrix MakeColumn(
70 Scalar m0, Scalar m1, Scalar m2, Scalar m3,
71 Scalar m4, Scalar m5, Scalar m6, Scalar m7,
72 Scalar m8, Scalar m9, Scalar m10, Scalar m11,
73 Scalar m12, Scalar m13, Scalar m14, Scalar m15){
74 return Matrix(m0, m1, m2, m3,
75 m4, m5, m6, m7,
76 m8, m9, m10, m11,
77 m12, m13, m14, m15);
78
79 }
80 // clang-format on
81
82 // clang-format off
83 static constexpr Matrix MakeRow(
84 Scalar m0, Scalar m1, Scalar m2, Scalar m3,
85 Scalar m4, Scalar m5, Scalar m6, Scalar m7,
86 Scalar m8, Scalar m9, Scalar m10, Scalar m11,
87 Scalar m12, Scalar m13, Scalar m14, Scalar m15){
88 return Matrix(m0, m4, m8, m12,
89 m1, m5, m9, m13,
90 m2, m6, m10, m14,
91 m3, m7, m11, m15);
92 }
93 // clang-format on
94
95 static constexpr Matrix MakeTranslation(const Vector3& t) {
96 // clang-format off
97 return Matrix(1.0f, 0.0f, 0.0f, 0.0f,
98 0.0f, 1.0f, 0.0f, 0.0f,
99 0.0f, 0.0f, 1.0f, 0.0f,
100 t.x, t.y, t.z, 1.0f);
101 // clang-format on
102 }
103
104 static constexpr Matrix MakeScale(const Vector3& s) {
105 // clang-format off
106 return Matrix(s.x, 0.0f, 0.0f, 0.0f,
107 0.0f, s.y, 0.0f, 0.0f,
108 0.0f, 0.0f, s.z, 0.0f,
109 0.0f, 0.0f, 0.0f, 1.0f);
110 // clang-format on
111 }
112
113 static constexpr Matrix MakeTranslateScale(const Vector3& s,
114 const Vector3& t) {
115 // clang-format off
116 return Matrix(s.x, 0.0f, 0.0f, 0.0f,
117 0.0f, s.y, 0.0f, 0.0f,
118 0.0f, 0.0f, s.z, 0.0f,
119 t.x , t.y, t.z, 1.0f);
120 // clang-format on
121 }
122
123 static constexpr Matrix MakeScale(const Vector2& s) {
124 return MakeScale(Vector3(s.x, s.y, 1.0f));
125 }
126
127 static constexpr Matrix MakeSkew(Scalar sx, Scalar sy) {
128 // clang-format off
129 return Matrix(1.0f, sy , 0.0f, 0.0f,
130 sx , 1.0f, 0.0f, 0.0f,
131 0.0f, 0.0f, 1.0f, 0.0f,
132 0.0f, 0.0f, 0.0f, 1.0f);
133 // clang-format on
134 }
135
136 static Matrix MakeRotation(Quaternion q) {
137 // clang-format off
138 return Matrix(
139 1.0f - 2.0f * q.y * q.y - 2.0f * q.z * q.z,
140 2.0f * q.x * q.y + 2.0f * q.z * q.w,
141 2.0f * q.x * q.z - 2.0f * q.y * q.w,
142 0.0f,
143
144 2.0f * q.x * q.y - 2.0f * q.z * q.w,
145 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z,
146 2.0f * q.y * q.z + 2.0f * q.x * q.w,
147 0.0f,
148
149 2.0f * q.x * q.z + 2.0f * q.y * q.w,
150 2.0f * q.y * q.z - 2.0f * q.x * q.w,
151 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y,
152 0.0f,
153
154 0.0f,
155 0.0f,
156 0.0f,
157 1.0f);
158 // clang-format on
159 }
160
161 static Matrix MakeRotation(Radians radians, const Vector4& r) {
162 const Vector4 v = r.Normalize();
163
164 const Vector2 cos_sin = CosSin(radians);
165 const Scalar cosine = cos_sin.x;
166 const Scalar cosp = 1.0f - cosine;
167 const Scalar sine = cos_sin.y;
168
169 // clang-format off
170 return Matrix(
171 cosine + cosp * v.x * v.x,
172 cosp * v.x * v.y + v.z * sine,
173 cosp * v.x * v.z - v.y * sine,
174 0.0f,
175
176 cosp * v.x * v.y - v.z * sine,
177 cosine + cosp * v.y * v.y,
178 cosp * v.y * v.z + v.x * sine,
179 0.0f,
180
181 cosp * v.x * v.z + v.y * sine,
182 cosp * v.y * v.z - v.x * sine,
183 cosine + cosp * v.z * v.z,
184 0.0f,
185
186 0.0f,
187 0.0f,
188 0.0f,
189 1.0f);
190 // clang-format on
191 }
192
193 static Matrix MakeRotationX(Radians r) {
194 const Vector2 cos_sin = CosSin(r);
195 const Scalar cosine = cos_sin.x;
196 const Scalar sine = cos_sin.y;
197
198 // clang-format off
199 return Matrix(
200 1.0f, 0.0f, 0.0f, 0.0f,
201 0.0f, cosine, sine, 0.0f,
202 0.0f, -sine, cosine, 0.0f,
203 0.0f, 0.0f, 0.0f, 1.0f
204 );
205 // clang-format on
206 }
207
208 static Matrix MakeRotationY(Radians r) {
209 const Vector2 cos_sin = CosSin(r);
210 const Scalar cosine = cos_sin.x;
211 const Scalar sine = cos_sin.y;
212
213 // clang-format off
214 return Matrix(
215 cosine, 0.0f, -sine, 0.0f,
216 0.0f, 1.0f, 0.0f, 0.0f,
217 sine, 0.0f, cosine, 0.0f,
218 0.0f, 0.0f, 0.0f, 1.0f
219 );
220 // clang-format on
221 }
222
223 static Matrix MakeRotationZ(Radians r) {
224 const Vector2 cos_sin = CosSin(r);
225 const Scalar cosine = cos_sin.x;
226 const Scalar sine = cos_sin.y;
227
228 // clang-format off
229 return Matrix (
230 cosine, sine, 0.0f, 0.0f,
231 -sine, cosine, 0.0f, 0.0f,
232 0.0f, 0.0f, 1.0f, 0.0f,
233 0.0f, 0.0f, 0.0f, 1.0
234 );
235 // clang-format on
236 }
237
238 /// The Matrix without its `w` components (without translation).
239 constexpr Matrix Basis() const {
240 // clang-format off
241 return Matrix(
242 m[0], m[1], m[2], 0.0f,
243 m[4], m[5], m[6], 0.0f,
244 m[8], m[9], m[10], 0.0f,
245 0.0f, 0.0f, 0.0f, 1.0
246 );
247 // clang-format on
248 }
249
250 // Converts the second row/col to identity to make this an equivalent
251 // to a Skia 3x3 Matrix.
252 constexpr Matrix To3x3() const {
253 // clang-format off
254 return Matrix(
255 m[0], m[1], 0, m[3],
256 m[4], m[5], 0, m[7],
257 0, 0, 1, 0,
258 m[12], m[13], 0, m[15]
259 );
260 // clang-format on
261 }
262
263 constexpr Matrix Translate(const Vector3& t) const {
264 // clang-format off
265 return Matrix(m[0], m[1], m[2], m[3],
266 m[4], m[5], m[6], m[7],
267 m[8], m[9], m[10], m[11],
268 m[0] * t.x + m[4] * t.y + m[8] * t.z + m[12],
269 m[1] * t.x + m[5] * t.y + m[9] * t.z + m[13],
270 m[2] * t.x + m[6] * t.y + m[10] * t.z + m[14],
271 m[3] * t.x + m[7] * t.y + m[11] * t.z + m[15]);
272 // clang-format on
273 }
274
275 constexpr Matrix Scale(const Vector3& s) const {
276 // clang-format off
277 return Matrix(m[0] * s.x, m[1] * s.x, m[2] * s.x, m[3] * s.x,
278 m[4] * s.y, m[5] * s.y, m[6] * s.y, m[7] * s.y,
279 m[8] * s.z, m[9] * s.z, m[10] * s.z, m[11] * s.z,
280 m[12] , m[13] , m[14] , m[15] );
281 // clang-format on
282 }
283
284 constexpr Matrix Multiply(const Matrix& o) const {
285 // clang-format off
286 return Matrix(
287 m[0] * o.m[0] + m[4] * o.m[1] + m[8] * o.m[2] + m[12] * o.m[3],
288 m[1] * o.m[0] + m[5] * o.m[1] + m[9] * o.m[2] + m[13] * o.m[3],
289 m[2] * o.m[0] + m[6] * o.m[1] + m[10] * o.m[2] + m[14] * o.m[3],
290 m[3] * o.m[0] + m[7] * o.m[1] + m[11] * o.m[2] + m[15] * o.m[3],
291 m[0] * o.m[4] + m[4] * o.m[5] + m[8] * o.m[6] + m[12] * o.m[7],
292 m[1] * o.m[4] + m[5] * o.m[5] + m[9] * o.m[6] + m[13] * o.m[7],
293 m[2] * o.m[4] + m[6] * o.m[5] + m[10] * o.m[6] + m[14] * o.m[7],
294 m[3] * o.m[4] + m[7] * o.m[5] + m[11] * o.m[6] + m[15] * o.m[7],
295 m[0] * o.m[8] + m[4] * o.m[9] + m[8] * o.m[10] + m[12] * o.m[11],
296 m[1] * o.m[8] + m[5] * o.m[9] + m[9] * o.m[10] + m[13] * o.m[11],
297 m[2] * o.m[8] + m[6] * o.m[9] + m[10] * o.m[10] + m[14] * o.m[11],
298 m[3] * o.m[8] + m[7] * o.m[9] + m[11] * o.m[10] + m[15] * o.m[11],
299 m[0] * o.m[12] + m[4] * o.m[13] + m[8] * o.m[14] + m[12] * o.m[15],
300 m[1] * o.m[12] + m[5] * o.m[13] + m[9] * o.m[14] + m[13] * o.m[15],
301 m[2] * o.m[12] + m[6] * o.m[13] + m[10] * o.m[14] + m[14] * o.m[15],
302 m[3] * o.m[12] + m[7] * o.m[13] + m[11] * o.m[14] + m[15] * o.m[15]);
303 // clang-format on
304 }
305
306 constexpr Matrix Transpose() const {
307 // clang-format off
308 return {
309 m[0], m[4], m[8], m[12],
310 m[1], m[5], m[9], m[13],
311 m[2], m[6], m[10], m[14],
312 m[3], m[7], m[11], m[15],
313 };
314 // clang-format on
315 }
316
317 Matrix Invert() const;
318
319 Scalar GetDeterminant() const;
320
321 bool IsInvertible() const { return GetDeterminant() != 0; }
322
323 inline Scalar GetMaxBasisLengthXY() const {
324 // The full basis computation requires computing the squared scaling factor
325 // for translate/scale only matrices. This substantially limits the range of
326 // precision for small and large scales. Instead, check for the common cases
327 // and directly return the max scaling factor.
328 if (e[0][1] == 0 && e[1][0] == 0) {
329 return std::max(std::abs(e[0][0]), std::abs(e[1][1]));
330 }
331 return std::sqrt(std::max(e[0][0] * e[0][0] + e[0][1] * e[0][1],
332 e[1][0] * e[1][0] + e[1][1] * e[1][1]));
333 }
334
335 constexpr Vector3 GetBasisX() const { return Vector3(m[0], m[1], m[2]); }
336
337 constexpr Vector3 GetBasisY() const { return Vector3(m[4], m[5], m[6]); }
338
339 constexpr Vector3 GetBasisZ() const { return Vector3(m[8], m[9], m[10]); }
340
341 inline Vector3 GetScale() const {
342 return Vector3(GetBasisX().GetLength(), GetBasisY().GetLength(),
343 GetBasisZ().GetLength());
344 }
345
346 inline Scalar GetDirectionScale(Vector3 direction) const {
347 return 1.0f / (this->Basis().Invert() * direction.Normalize()).GetLength() *
348 direction.GetLength();
349 }
350
351 inline bool IsFinite() const {
352 return vec[0].IsFinite() && vec[1].IsFinite() && vec[2].IsFinite() &&
353 vec[3].IsFinite();
354 }
355
356 constexpr bool IsAffine() const {
357 return (m[2] == 0 && m[3] == 0 && m[6] == 0 && m[7] == 0 && m[8] == 0 &&
358 m[9] == 0 && m[10] == 1 && m[11] == 0 && m[14] == 0 && m[15] == 1);
359 }
360
361 constexpr bool HasPerspective2D() const {
362 return m[3] != 0 || m[7] != 0 || m[15] != 1;
363 }
364
365 constexpr bool HasPerspective() const {
366 return m[3] != 0 || m[7] != 0 || m[11] != 0 || m[15] != 1;
367 }
368
369 constexpr bool HasTranslation() const { return m[12] != 0 || m[13] != 0; }
370
371 constexpr bool IsAligned2D(Scalar tolerance = 0) const {
372 if (HasPerspective2D()) {
373 return false;
374 }
375 if (ScalarNearlyZero(m[1], tolerance) &&
376 ScalarNearlyZero(m[4], tolerance)) {
377 return true;
378 }
379 if (ScalarNearlyZero(m[0], tolerance) &&
380 ScalarNearlyZero(m[5], tolerance)) {
381 return true;
382 }
383 return false;
384 }
385
386 constexpr bool IsAligned(Scalar tolerance = 0) const {
387 if (HasPerspective()) {
388 return false;
389 }
390 int v[] = {!ScalarNearlyZero(m[0], tolerance), //
391 !ScalarNearlyZero(m[1], tolerance), //
392 !ScalarNearlyZero(m[2], tolerance), //
393 !ScalarNearlyZero(m[4], tolerance), //
394 !ScalarNearlyZero(m[5], tolerance), //
395 !ScalarNearlyZero(m[6], tolerance), //
396 !ScalarNearlyZero(m[8], tolerance), //
397 !ScalarNearlyZero(m[9], tolerance), //
398 !ScalarNearlyZero(m[10], tolerance)};
399 // Check if all three basis vectors are aligned to an axis.
400 if (v[0] + v[1] + v[2] != 1 || //
401 v[3] + v[4] + v[5] != 1 || //
402 v[6] + v[7] + v[8] != 1) {
403 return false;
404 }
405 // Ensure that none of the basis vectors overlap.
406 if (v[0] + v[3] + v[6] != 1 || //
407 v[1] + v[4] + v[7] != 1 || //
408 v[2] + v[5] + v[8] != 1) {
409 return false;
410 }
411 return true;
412 }
413
414 constexpr bool IsIdentity() const {
415 return (
416 // clang-format off
417 m[0] == 1.0f && m[1] == 0.0f && m[2] == 0.0f && m[3] == 0.0f &&
418 m[4] == 0.0f && m[5] == 1.0f && m[6] == 0.0f && m[7] == 0.0f &&
419 m[8] == 0.0f && m[9] == 0.0f && m[10] == 1.0f && m[11] == 0.0f &&
420 m[12] == 0.0f && m[13] == 0.0f && m[14] == 0.0f && m[15] == 1.0f
421 // clang-format on
422 );
423 }
424
425 /// @brief Returns true if the matrix has no entries other than translation
426 /// components. Note that an identity matrix meets this criteria.
427 constexpr bool IsTranslationOnly() const {
428 return (
429 // clang-format off
430 m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 0.0 &&
431 m[4] == 0.0 && m[5] == 1.0 && m[6] == 0.0 && m[7] == 0.0 &&
432 m[8] == 0.0 && m[9] == 0.0 && m[10] == 1.0 && m[11] == 0.0 &&
433 m[15] == 1.0
434 // clang-format on
435 );
436 }
437
438 /// @brief Returns true if the matrix has a scale-only basis and is
439 /// non-projective. Note that an identity matrix meets this criteria.
440 constexpr bool IsTranslationScaleOnly() const {
441 return (
442 // clang-format off
443 m[0] != 0.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 0.0 &&
444 m[4] == 0.0 && m[5] != 0.0 && m[6] == 0.0 && m[7] == 0.0 &&
445 m[8] == 0.0 && m[9] == 0.0 && m[10] != 0.0 && m[11] == 0.0 &&
446 m[15] == 1.0
447 // clang-format on
448 );
449 }
450
451 std::optional<MatrixDecomposition> Decompose() const;
452
453 bool Equals(const Matrix& matrix, Scalar epsilon = 1e-5f) const {
454 const Scalar* a = m;
455 const Scalar* b = matrix.m;
456 return ScalarNearlyEqual(a[0], b[0], epsilon) &&
457 ScalarNearlyEqual(a[1], b[1], epsilon) &&
458 ScalarNearlyEqual(a[2], b[2], epsilon) &&
459 ScalarNearlyEqual(a[3], b[3], epsilon) &&
460 ScalarNearlyEqual(a[4], b[4], epsilon) &&
461 ScalarNearlyEqual(a[5], b[5], epsilon) &&
462 ScalarNearlyEqual(a[6], b[6], epsilon) &&
463 ScalarNearlyEqual(a[7], b[7], epsilon) &&
464 ScalarNearlyEqual(a[8], b[8], epsilon) &&
465 ScalarNearlyEqual(a[9], b[9], epsilon) &&
466 ScalarNearlyEqual(a[10], b[10], epsilon) &&
467 ScalarNearlyEqual(a[11], b[11], epsilon) &&
468 ScalarNearlyEqual(a[12], b[12], epsilon) &&
469 ScalarNearlyEqual(a[13], b[13], epsilon) &&
470 ScalarNearlyEqual(a[14], b[14], epsilon) &&
471 ScalarNearlyEqual(a[15], b[15], epsilon);
472 }
473
474 constexpr bool operator==(const Matrix& m) const {
475 // clang-format off
476 return vec[0] == m.vec[0]
477 && vec[1] == m.vec[1]
478 && vec[2] == m.vec[2]
479 && vec[3] == m.vec[3];
480 // clang-format on
481 }
482
483 constexpr bool operator!=(const Matrix& m) const {
484 // clang-format off
485 return vec[0] != m.vec[0]
486 || vec[1] != m.vec[1]
487 || vec[2] != m.vec[2]
488 || vec[3] != m.vec[3];
489 // clang-format on
490 }
491
492 Matrix operator+(const Vector3& t) const { return Translate(t); }
493
494 Matrix operator-(const Vector3& t) const { return Translate(-t); }
495
496 Matrix operator*(const Matrix& m) const { return Multiply(m); }
497
498 Matrix operator+(const Matrix& m) const;
499
500 constexpr Vector4 operator*(const Vector4& v) const {
501 return Vector4(v.x * m[0] + v.y * m[4] + v.z * m[8] + v.w * m[12],
502 v.x * m[1] + v.y * m[5] + v.z * m[9] + v.w * m[13],
503 v.x * m[2] + v.y * m[6] + v.z * m[10] + v.w * m[14],
504 v.x * m[3] + v.y * m[7] + v.z * m[11] + v.w * m[15]);
505 }
506
507 constexpr Vector3 operator*(const Vector3& v) const {
508 Scalar w = v.x * m[3] + v.y * m[7] + v.z * m[11] + m[15];
509 Vector3 result(v.x * m[0] + v.y * m[4] + v.z * m[8] + m[12],
510 v.x * m[1] + v.y * m[5] + v.z * m[9] + m[13],
511 v.x * m[2] + v.y * m[6] + v.z * m[10] + m[14]);
512
513 // This is Skia's behavior, but it may be reasonable to allow UB for the w=0
514 // case.
515 if (w) {
516 w = 1 / w;
517 }
518 return result * w;
519 }
520
521 constexpr Point operator*(const Point& v) const {
522 Scalar w = v.x * m[3] + v.y * m[7] + m[15];
523 Point result(v.x * m[0] + v.y * m[4] + m[12],
524 v.x * m[1] + v.y * m[5] + m[13]);
525
526 // This is Skia's behavior, but it may be reasonable to allow UB for the w=0
527 // case.
528 if (w) {
529 w = 1 / w;
530 }
531 return result * w;
532 }
533
534 constexpr Vector3 TransformHomogenous(const Point& v) const {
535 return Vector3(v.x * m[0] + v.y * m[4] + m[12],
536 v.x * m[1] + v.y * m[5] + m[13],
537 v.x * m[3] + v.y * m[7] + m[15]);
538 }
539
540 constexpr Vector4 TransformDirection(const Vector4& v) const {
541 return Vector4(v.x * m[0] + v.y * m[4] + v.z * m[8],
542 v.x * m[1] + v.y * m[5] + v.z * m[9],
543 v.x * m[2] + v.y * m[6] + v.z * m[10], v.w);
544 }
545
546 constexpr Vector3 TransformDirection(const Vector3& v) const {
547 return Vector3(v.x * m[0] + v.y * m[4] + v.z * m[8],
548 v.x * m[1] + v.y * m[5] + v.z * m[9],
549 v.x * m[2] + v.y * m[6] + v.z * m[10]);
550 }
551
552 constexpr Vector2 TransformDirection(const Vector2& v) const {
553 return Vector2(v.x * m[0] + v.y * m[4], v.x * m[1] + v.y * m[5]);
554 }
555
556 constexpr Quad Transform(const Quad& quad) const {
557 return {
558 *this * quad[0],
559 *this * quad[1],
560 *this * quad[2],
561 *this * quad[3],
562 };
563 }
564
565 template <class T>
566 static constexpr Matrix MakeOrthographic(TSize<T> size) {
567 // Per assumptions about NDC documented above.
568 const auto scale =
569 MakeScale({2.0f / static_cast<Scalar>(size.width),
570 -2.0f / static_cast<Scalar>(size.height), 0.0f});
571 const auto translate = MakeTranslation({-1.0f, 1.0f, 0.5f});
572 return translate * scale;
573 }
574
575 static inline Matrix MakePerspective(Radians fov_y,
576 Scalar aspect_ratio,
577 Scalar z_near,
578 Scalar z_far) {
579 Scalar height = std::tan(fov_y.radians * 0.5f);
580 Scalar width = height * aspect_ratio;
581
582 // clang-format off
583 return {
584 1.0f / width, 0.0f, 0.0f, 0.0f,
585 0.0f, 1.0f / height, 0.0f, 0.0f,
586 0.0f, 0.0f, z_far / (z_far - z_near), 1.0f,
587 0.0f, 0.0f, -(z_far * z_near) / (z_far - z_near), 0.0f,
588 };
589 // clang-format on
590 }
591
592 template <class T>
593 static constexpr Matrix MakePerspective(Radians fov_y,
594 TSize<T> size,
595 Scalar z_near,
596 Scalar z_far) {
597 return MakePerspective(fov_y, static_cast<Scalar>(size.width) / size.height,
598 z_near, z_far);
599 }
600
601 static inline Matrix MakeLookAt(Vector3 position,
602 Vector3 target,
603 Vector3 up) {
604 Vector3 forward = (target - position).Normalize();
605 Vector3 right = up.Cross(forward);
606 up = forward.Cross(right);
607
608 // clang-format off
609 return {
610 right.x, up.x, forward.x, 0.0f,
611 right.y, up.y, forward.y, 0.0f,
612 right.z, up.z, forward.z, 0.0f,
613 -right.Dot(position), -up.Dot(position), -forward.Dot(position), 1.0f
614 };
615 // clang-format on
616 }
617
618 static inline Vector2 CosSin(Radians radians) {
619 // The precision of a float around 1.0 is much lower than it is
620 // around 0.0, so we end up with cases on quadrant rotations where
621 // we get a +/-1.0 for one of the values and a non-zero value for
622 // the other. This happens around quadrant rotations which makes it
623 // especially common and results in unclean quadrant rotation
624 // matrices which do not return true from |IsAligned[2D]| even
625 // though that is exactly where you need them to exhibit that property.
626 // It also injects small floating point mantissa errors into the
627 // matrices whenever you concatenate them with a quadrant rotation.
628 //
629 // This issue is also exacerbated by the fact that, in radians, the
630 // angles for quadrant rotations are irrational numbers. The measuring
631 // error for representing 90 degree multiples is small enough that
632 // either sin or cos will return a value near +/-1.0, but not small
633 // enough that the other value will be a clean 0.0.
634 //
635 // Some geometry packages simply discard very small numbers from
636 // sin/cos, but the following approach specifically targets just the
637 // area around a quadrant rotation (where either the sin or cos are
638 // measuring as +/-1.0) for symmetry of precision.
639
640 Scalar sin = std::sin(radians.radians);
641 if (std::abs(sin) == 1.0f) {
642 // 90 or 270 degrees (mod 360)
643 return {0.0f, sin};
644 } else {
645 Scalar cos = std::cos(radians.radians);
646 if (std::abs(cos) == 1.0f) {
647 // 0 or 180 degrees (mod 360)
648 return {cos, 0.0f};
649 }
650 return {cos, sin};
651 }
652 }
653 };
654
655 static_assert(sizeof(struct Matrix) == sizeof(Scalar) * 16,
656 "The matrix must be of consistent size.");
657
658 } // namespace impeller
659
660 namespace std {
661 inline std::ostream& operator<<(std::ostream& out, const impeller::Matrix& m) {
662 out << "(" << std::endl << std::fixed;
663 for (size_t i = 0; i < 4u; i++) {
664 for (size_t j = 0; j < 4u; j++) {
665 out << std::setw(15) << m.e[j][i] << ",";
666 }
667 out << std::endl;
668 }
669 out << ")";
670 return out;
671 }
672
673 } // namespace std
674
675 #endif // FLUTTER_IMPELLER_GEOMETRY_MATRIX_H_
matrix_decomposition.h
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller
Definition: allocation.cc:12
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::ScalarNearlyZero
constexpr bool ScalarNearlyZero(Scalar x, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:31
impeller::ScalarNearlyEqual
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:36
impeller::Quad
std::array< Point, 4 > Quad
Definition: point.h:332
std
Definition: comparable.h:95
std::operator<<
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
Definition: arc.h:141
point.h
quaternion.h
scalar.h
shear.h
size.h
impeller::MatrixDecomposition
Definition: matrix_decomposition.h:15
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::IsTranslationOnly
constexpr bool IsTranslationOnly() const
Returns true if the matrix has no entries other than translation components. Note that an identity ma...
Definition: matrix.h:427
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:566
impeller::Matrix::Multiply
constexpr Matrix Multiply(const Matrix &o) const
Definition: matrix.h:284
impeller::Matrix::IsAffine
constexpr bool IsAffine() const
Definition: matrix.h:356
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::GetBasisY
constexpr Vector3 GetBasisY() const
Definition: matrix.h:337
impeller::Matrix::Matrix
constexpr Matrix()
Definition: matrix.h:47
impeller::Matrix::IsIdentity
constexpr bool IsIdentity() const
Definition: matrix.h:414
impeller::Matrix::IsTranslationScaleOnly
constexpr bool IsTranslationScaleOnly() const
Returns true if the matrix has a scale-only basis and is non-projective. Note that an identity matrix...
Definition: matrix.h:440
impeller::Matrix::m
Scalar m[16]
Definition: matrix.h:39
impeller::Matrix::HasTranslation
constexpr bool HasTranslation() const
Definition: matrix.h:369
impeller::Matrix::Translate
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:263
impeller::Matrix::IsInvertible
bool IsInvertible() const
Definition: matrix.h:321
impeller::Matrix::TransformDirection
constexpr Vector2 TransformDirection(const Vector2 &v) const
Definition: matrix.h:552
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector2 &s)
Definition: matrix.h:123
impeller::Matrix::operator+
Matrix operator+(const Vector3 &t) const
Definition: matrix.h:492
impeller::Matrix::GetDirectionScale
Scalar GetDirectionScale(Vector3 direction) const
Definition: matrix.h:346
impeller::Matrix::Basis
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:239
impeller::Matrix::Matrix
constexpr Matrix(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:56
impeller::Matrix::operator*
Matrix operator*(const Matrix &m) const
Definition: matrix.h:496
impeller::Matrix::IsAligned
constexpr bool IsAligned(Scalar tolerance=0) const
Definition: matrix.h:386
impeller::Matrix::Invert
Matrix Invert() const
Definition: matrix.cc:97
impeller::Matrix::MakeColumn
static constexpr Matrix MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:69
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:208
impeller::Matrix::GetBasisZ
constexpr Vector3 GetBasisZ() const
Definition: matrix.h:339
impeller::Matrix::vec
Vector4 vec[4]
Definition: matrix.h:41
impeller::Matrix::Decompose
std::optional< MatrixDecomposition > Decompose() const
Definition: matrix.cc:200
impeller::Matrix::HasPerspective2D
constexpr bool HasPerspective2D() const
Definition: matrix.h:361
impeller::Matrix::IsFinite
bool IsFinite() const
Definition: matrix.h:351
impeller::Matrix::operator-
Matrix operator-(const Vector3 &t) const
Definition: matrix.h:494
impeller::Matrix::operator*
constexpr Vector4 operator*(const Vector4 &v) const
Definition: matrix.h:500
impeller::Matrix::CosSin
static Vector2 CosSin(Radians radians)
Definition: matrix.h:618
impeller::Matrix::operator!=
constexpr bool operator!=(const Matrix &m) const
Definition: matrix.h:483
impeller::Matrix::MakePerspective
static Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:575
impeller::Matrix::operator*
constexpr Point operator*(const Point &v) const
Definition: matrix.h:521
impeller::Matrix::operator*
constexpr Vector3 operator*(const Vector3 &v) const
Definition: matrix.h:507
impeller::Matrix::TransformDirection
constexpr Vector3 TransformDirection(const Vector3 &v) const
Definition: matrix.h:546
impeller::Matrix::MakeRow
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:83
impeller::Matrix::GetScale
Vector3 GetScale() const
Definition: matrix.h:341
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:127
impeller::Matrix::Transform
constexpr Quad Transform(const Quad &quad) const
Definition: matrix.h:556
impeller::Matrix::operator==
constexpr bool operator==(const Matrix &m) const
Definition: matrix.h:474
impeller::Matrix::Scale
constexpr Matrix Scale(const Vector3 &s) const
Definition: matrix.h:275
impeller::Matrix::TransformHomogenous
constexpr Vector3 TransformHomogenous(const Point &v) const
Definition: matrix.h:534
impeller::Matrix::MakeTranslateScale
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
Definition: matrix.h:113
impeller::Matrix::e
Scalar e[4][4]
Definition: matrix.h:40
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
impeller::Matrix::MakeRotation
static Matrix MakeRotation(Radians radians, const Vector4 &r)
Definition: matrix.h:161
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, TSize< T > size, Scalar z_near, Scalar z_far)
Definition: matrix.h:593
impeller::Matrix::GetDeterminant
Scalar GetDeterminant() const
Definition: matrix.cc:162
impeller::Matrix::HasPerspective
constexpr bool HasPerspective() const
Definition: matrix.h:365
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::Matrix::MakeLookAt
static Matrix MakeLookAt(Vector3 position, Vector3 target, Vector3 up)
Definition: matrix.h:601
impeller::Matrix::TransformDirection
constexpr Vector4 TransformDirection(const Vector4 &v) const
Definition: matrix.h:540
impeller::Matrix::GetBasisX
constexpr Vector3 GetBasisX() const
Definition: matrix.h:335
impeller::Matrix::Equals
bool Equals(const Matrix &matrix, Scalar epsilon=1e-5f) const
Definition: matrix.h:453
impeller::Matrix::To3x3
constexpr Matrix To3x3() const
Definition: matrix.h:252
impeller::Matrix::IsAligned2D
constexpr bool IsAligned2D(Scalar tolerance=0) const
Definition: matrix.h:371
impeller::Matrix::MakeRotation
static Matrix MakeRotation(Quaternion q)
Definition: matrix.h:136
impeller::Matrix::Transpose
constexpr Matrix Transpose() const
Definition: matrix.h:306
impeller::Matrix::GetMaxBasisLengthXY
Scalar GetMaxBasisLengthXY() const
Definition: matrix.h:323
impeller::Matrix::MakeRotationX
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:193
impeller::Quaternion
Definition: quaternion.h:14
impeller::Quaternion::y
Scalar y
Definition: quaternion.h:18
impeller::Quaternion::z
Scalar z
Definition: quaternion.h:19
impeller::Quaternion::w
Scalar w
Definition: quaternion.h:20
impeller::Quaternion::x
Scalar x
Definition: quaternion.h:17
impeller::Radians
Definition: scalar.h:44
impeller::Radians::radians
Scalar radians
Definition: scalar.h:45
impeller::TPoint< Scalar >
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TSize
Definition: size.h:25
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TSize::width
Type width
Definition: size.h:28
impeller::Vector3
Definition: vector.h:20
impeller::Vector3::Normalize
Vector3 Normalize() const
Definition: vector.h:49
impeller::Vector3::x
Scalar x
Definition: vector.h:23
impeller::Vector3::Cross
constexpr Vector3 Cross(const Vector3 &other) const
Definition: vector.h:62
impeller::Vector3::y
Scalar y
Definition: vector.h:24
impeller::Vector3::Dot
constexpr Scalar Dot(const Vector3 &other) const
Definition: vector.h:54
impeller::Vector3::GetLength
Scalar GetLength() const
Definition: vector.h:47
impeller::Vector3::z
Scalar z
Definition: vector.h:25
impeller::Vector4
Definition: vector.h:232
impeller::Vector4::IsFinite
bool IsFinite() const
Definition: vector.h:258
impeller::Vector4::Normalize
Vector4 Normalize() const
Definition: vector.h:263
impeller::Vector4::y
Scalar y
Definition: vector.h:236
impeller::Vector4::w
Scalar w
Definition: vector.h:238
impeller::Vector4::x
Scalar x
Definition: vector.h:235
impeller::Vector4::z
Scalar z
Definition: vector.h:237
vector.h