Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
Mat4.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cassert>
4#include <cmath>
5#include <cstddef>
6#include <optional>
7#include <type_traits>
8
9#include <mv/math/Vec4.hpp>
10#include <mv/math/detail/Matrix4Ops.hpp>
11
12namespace mv::math
13{
14 template <typename T>
15 requires std::is_floating_point_v<T>
16 class Mat4
17 {
18 public:
19 using Component = T;
21
22 constexpr Mat4() noexcept :
23 Rows_{RowVector(T(1), T(0), T(0), T(0)),
24 RowVector(T(0), T(1), T(0), T(0)),
25 RowVector(T(0), T(0), T(1), T(0)),
26 RowVector(T(0), T(0), T(0), T(1))}
27 {
28 }
29
30 constexpr Mat4(const RowVector& row0,
31 const RowVector& row1,
32 const RowVector& row2,
33 const RowVector& row3) noexcept :
34 Rows_{row0, row1, row2, row3}
35 {
36 }
37
38 constexpr Mat4(T m11,
39 T m12,
40 T m13,
41 T m14,
42 T m21,
43 T m22,
44 T m23,
45 T m24,
46 T m31,
47 T m32,
48 T m33,
49 T m34,
50 T m41,
51 T m42,
52 T m43,
53 T m44) noexcept :
58 {
59 }
60
61 [[nodiscard]] static constexpr Mat4 Identity() noexcept
62 {
63 return Mat4();
64 }
65
66 [[nodiscard]] static constexpr Mat4 Zero() noexcept
67 {
68 return Mat4(RowVector(), RowVector(), RowVector(), RowVector());
69 }
70
71 [[nodiscard]] constexpr const RowVector& Row(
72 std::size_t index) const noexcept
73 {
74 assert(index < 4U);
75 return Rows_[index];
76 }
77
78 [[nodiscard]] constexpr RowVector Column(
79 std::size_t index) const noexcept
80 {
81 assert(index < 4U);
82 return RowVector(
83 ComponentAt(Rows_[0], index), ComponentAt(Rows_[1], index),
84 ComponentAt(Rows_[2], index), ComponentAt(Rows_[3], index));
85 }
86
87 [[nodiscard]] constexpr T Element(std::size_t row,
88 std::size_t column) const noexcept
89 {
90 return ComponentAt(Row(row), column);
91 }
92
94 const RowVector& vector) const noexcept
95 {
96 using Ops = detail::Matrix4Ops<T>;
97 if constexpr (Ops::HasNative)
98 {
99 return RowVector::FromNative(
100 Ops::Transform(vector.Components_, Rows_[0].Components_,
101 Rows_[1].Components_, Rows_[2].Components_,
102 Rows_[3].Components_));
103 }
104
105 return Rows_[0] * vector.X() + Rows_[1] * vector.Y() +
106 Rows_[2] * vector.Z() + Rows_[3] * vector.W();
107 }
108
109 [[nodiscard]] Mat4 operator*(const Mat4& right) const noexcept
110 {
111 using Ops = detail::Matrix4Ops<T>;
112 if constexpr (Ops::HasNative)
113 {
114 return FromNativeRows(Ops::Multiply(
115 Rows_[0].Components_, Rows_[1].Components_,
116 Rows_[2].Components_, Rows_[3].Components_,
117 right.Rows_[0].Components_, right.Rows_[1].Components_,
118 right.Rows_[2].Components_, right.Rows_[3].Components_));
119 }
120
121 return Mat4(right.TransformHomogeneous(Rows_[0]),
122 right.TransformHomogeneous(Rows_[1]),
123 right.TransformHomogeneous(Rows_[2]),
124 right.TransformHomogeneous(Rows_[3]));
125 }
126
128 {
129 using Ops = detail::Matrix4Ops<T>;
130 if constexpr (Ops::HasNative)
131 {
132 return FromNativeRows(
133 Ops::Transpose(Rows_[0].Components_, Rows_[1].Components_,
134 Rows_[2].Components_, Rows_[3].Components_));
135 }
136 return Mat4(Column(0U), Column(1U), Column(2U), Column(3U));
137 }
138
140 {
141 using Ops = detail::Matrix4Ops<T>;
142 if constexpr (Ops::HasNative)
143 {
144 return Ops::Determinant(
145 Rows_[0].Components_, Rows_[1].Components_,
146 Rows_[2].Components_, Rows_[3].Components_);
147 }
148
149 return Element(0U, 0U) * MinorDeterminant(0U, 0U) -
150 Element(0U, 1U) * MinorDeterminant(0U, 1U) +
151 Element(0U, 2U) * MinorDeterminant(0U, 2U) -
152 Element(0U, 3U) * MinorDeterminant(0U, 3U);
153 }
154
155 [[nodiscard]] std::optional<Mat4> TryInverse() const noexcept
156 {
157 using Ops = detail::Matrix4Ops<T>;
158 if constexpr (Ops::HasNative)
159 {
160 const typename Ops::Rows inverse = Ops::InverseUnchecked(
161 Rows_[0].Components_, Rows_[1].Components_,
162 Rows_[2].Components_, Rows_[3].Components_);
163 if (!Ops::IsFinite(inverse))
164 {
165 return std::nullopt;
166 }
167 return FromNativeRows(inverse);
168 }
169
170 const T determinant = Determinant();
171 if (determinant == T(0) || !std::isfinite(determinant))
172 {
173 return std::nullopt;
174 }
175
176 // Adjugate/cofactor identity independently expressed and
177 // cross-checked against RTM 2.3.1 matrix_inverse (MIT, commit
178 // 745bd25673d93b46941eda55e0993327dbc12b53b).
180 T values[16]{};
181 bool finite = true;
182 for (std::size_t row = 0U; row < 4U; ++row)
183 {
184 for (std::size_t column = 0U; column < 4U; ++column)
185 {
186 const T sign = ((row + column) & 1U) == 0U ? T(1) : T(-1);
187 const T value = sign * MinorDeterminant(column, row) *
189 values[row * 4U + column] = value;
190 finite &= std::isfinite(value);
191 }
192 }
193 if (!finite)
194 {
195 return std::nullopt;
196 }
197 return Mat4(
198 RowVector(values[0], values[1], values[2], values[3]),
199 RowVector(values[4], values[5], values[6], values[7]),
200 RowVector(values[8], values[9], values[10], values[11]),
201 RowVector(values[12], values[13], values[14], values[15]));
202 }
203
205 {
206 bool finite = true;
207 for (std::size_t row = 0U; row < 4U; ++row)
208 {
209 for (std::size_t column = 0U; column < 4U; ++column)
210 {
211 finite &= std::isfinite(Element(row, column));
212 }
213 }
214 return finite;
215 }
216
217 [[nodiscard]] friend constexpr bool operator==(
218 const Mat4&, const Mat4&) noexcept = default;
219
220 private:
221 [[nodiscard]] static constexpr T ComponentAt(const RowVector& value,
222 std::size_t index) noexcept
223 {
224 assert(index < 4U);
225 if (index == 0U)
226 {
227 return value.X();
228 }
229 if (index == 1U)
230 {
231 return value.Y();
232 }
233 if (index == 2U)
234 {
235 return value.Z();
236 }
237 return value.W();
238 }
239
240 [[nodiscard]] T MinorDeterminant(
241 std::size_t removedRow, std::size_t removedColumn) const noexcept
242 {
243 T minor[9]{};
244 std::size_t destination = 0U;
245 for (std::size_t row = 0U; row < 4U; ++row)
246 {
247 if (row == removedRow)
248 {
249 continue;
250 }
251 for (std::size_t column = 0U; column < 4U; ++column)
252 {
253 if (column != removedColumn)
254 {
255 minor[destination++] = Element(row, column);
256 }
257 }
258 }
259 return minor[0] * (minor[4] * minor[8] - minor[5] * minor[7]) -
260 minor[1] * (minor[3] * minor[8] - minor[5] * minor[6]) +
261 minor[2] * (minor[3] * minor[7] - minor[4] * minor[6]);
262 }
263
264 template <typename Ops = detail::Matrix4Ops<T>>
265 [[nodiscard]] static Mat4 FromNativeRows(
266 const typename Ops::Rows& rows) noexcept
267 requires Ops::HasNative
268 {
269 return Mat4(RowVector::FromNative(rows.Row0),
270 RowVector::FromNative(rows.Row1),
271 RowVector::FromNative(rows.Row2),
272 RowVector::FromNative(rows.Row3));
273 }
274
275 RowVector Rows_[4];
276 };
277
278 template <typename T>
279 requires std::is_floating_point_v<T>
281 const Mat4<T>& matrix) noexcept
282 {
283 return matrix.TransformHomogeneous(vector);
284 }
285
288} // namespace mv::math
289
290static_assert(sizeof(mv::math::Mat4f) == 64);
291static_assert(alignof(mv::math::Mat4f) == 16);
292static_assert(std::is_trivially_copyable_v<mv::math::Mat4f>);
293static_assert(std::is_standard_layout_v<mv::math::Mat4f>);
294static_assert(sizeof(mv::math::Mat4d) == 128);
295static_assert(alignof(mv::math::Mat4d) == 32);
296static_assert(std::is_trivially_copyable_v<mv::math::Mat4d>);
297static_assert(std::is_standard_layout_v<mv::math::Mat4d>);
Mat4 operator*(const Mat4 &right) const noexcept
Definition Mat4.hpp:109
static constexpr Mat4 Zero() noexcept
Definition Mat4.hpp:66
static constexpr Mat4 Identity() noexcept
Definition Mat4.hpp:61
T Determinant() const noexcept
Definition Mat4.hpp:139
constexpr Mat4(T m11, T m12, T m13, T m14, T m21, T m22, T m23, T m24, T m31, T m32, T m33, T m34, T m41, T m42, T m43, T m44) noexcept
Definition Mat4.hpp:38
std::optional< Mat4 > TryInverse() const noexcept
Definition Mat4.hpp:155
constexpr const RowVector & Row(std::size_t index) const noexcept
Definition Mat4.hpp:71
friend constexpr bool operator==(const Mat4 &, const Mat4 &) noexcept=default
constexpr T Element(std::size_t row, std::size_t column) const noexcept
Definition Mat4.hpp:87
Vec4< T > RowVector
Definition Mat4.hpp:20
RowVector TransformHomogeneous(const RowVector &vector) const noexcept
Definition Mat4.hpp:93
constexpr RowVector Column(std::size_t index) const noexcept
Definition Mat4.hpp:78
constexpr Mat4() noexcept
Definition Mat4.hpp:22
bool IsFinite() const noexcept
Definition Mat4.hpp:204
Mat4 Transposed() const noexcept
Definition Mat4.hpp:127
constexpr Mat4(const RowVector &row0, const RowVector &row1, const RowVector &row2, const RowVector &row3) noexcept
Definition Mat4.hpp:30
Mat4< float > Mat4f
Definition Mat4.hpp:286
Vec3< T > operator*(const Vec3< T > &vector, const Mat3< T > &matrix) noexcept
Definition Mat3.hpp:266
Mat4< double > Mat4d
Definition Mat4.hpp:287