Nexus Engine  v0.0.1
Loading...
Searching...
No Matches
Quaternion.inl
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2
3#pragma once
4
5namespace Nexus {
6
7 template <std::floating_point T>
8 constexpr Quaternion<T>::Quaternion(T x, T y, T z, T w) : m_x(x),
9 m_y(y),
10 m_z(z),
11 m_w(w) {}
12
13 template <std::floating_point T>
14 template <std::floating_point U>
15 constexpr Quaternion<T>::Quaternion(const Vec3<U>& axis, U angleRadians) {
16 *this = FromAxisAngle(axis, angleRadians);
17 }
18
19 template <std::floating_point T>
21 return Quaternion(T{0}, T{0}, T{0}, T{1});
22 }
23
24 template <std::floating_point T>
25 template <std::floating_point U>
26 constexpr Quaternion<T> Quaternion<T>::FromEuler(U pitch, U yaw, U roll) {
27 const U halfPitch = pitch * U{0.5};
28 const U halfYaw = yaw * U{0.5};
29 const U halfRoll = roll * U{0.5};
30
31 const U sp = std::sin(halfPitch);
32 const U cp = std::cos(halfPitch);
33 const U sy = std::sin(halfYaw);
34 const U cy = std::cos(halfYaw);
35 const U sr = std::sin(halfRoll);
36 const U cr = std::cos(halfRoll);
37
38 return Quaternion(static_cast<T>(sp * cy * cr - cp * sy * sr), static_cast<T>(cp * sy * cr + sp * cy * sr),
39 static_cast<T>(cp * cy * sr - sp * sy * cr), static_cast<T>(cp * cy * cr + sp * sy * sr));
40 }
41
42 template <std::floating_point T>
43 template <std::floating_point U>
44 constexpr Quaternion<T> Quaternion<T>::FromAxisAngle(const Vec3<U>& axis, U angleRadians) {
45 const U halfAngle = angleRadians * U{0.5};
46 const U s = std::sin(halfAngle);
47 const U c = std::cos(halfAngle);
48
49 Vec3<U> normalizedAxis = axis;
50 const U lengthSquared = normalizedAxis[0] * normalizedAxis[0] + normalizedAxis[1] * normalizedAxis[1] +
51 normalizedAxis[2] * normalizedAxis[2];
52
53 if (lengthSquared > U{0}) {
54 const U invLength = U{1} / std::sqrt(lengthSquared);
55 normalizedAxis *= invLength;
56 }
57
58 return Quaternion(static_cast<T>(normalizedAxis[0] * s), static_cast<T>(normalizedAxis[1] * s),
59 static_cast<T>(normalizedAxis[2] * s), static_cast<T>(c));
60 }
61
62 template <std::floating_point T>
63 constexpr T& Quaternion<T>::X() {
64 return m_x;
65 }
66
67 template <std::floating_point T>
68 constexpr const T& Quaternion<T>::X() const {
69 return m_x;
70 }
71
72 template <std::floating_point T>
73 constexpr T& Quaternion<T>::Y() {
74 return m_y;
75 }
76
77 template <std::floating_point T>
78 constexpr const T& Quaternion<T>::Y() const {
79 return m_y;
80 }
81
82 template <std::floating_point T>
83 constexpr T& Quaternion<T>::Z() {
84 return m_z;
85 }
86
87 template <std::floating_point T>
88 constexpr const T& Quaternion<T>::Z() const {
89 return m_z;
90 }
91
92 template <std::floating_point T>
93 constexpr T& Quaternion<T>::W() {
94 return m_w;
95 }
96
97 template <std::floating_point T>
98 constexpr const T& Quaternion<T>::W() const {
99 return m_w;
100 }
101
102 template <std::floating_point T>
103 constexpr T* Quaternion<T>::Data() {
104 return &m_x;
105 }
106
107 template <std::floating_point T>
108 constexpr const T* Quaternion<T>::Data() const {
109 return &m_x;
110 }
111
112 template <std::floating_point T>
114 return 4;
115 }
116
117 template <std::floating_point T>
118 template <std::floating_point U>
119 constexpr bool Quaternion<T>::operator==(const Quaternion<U>& other) const {
120 return m_x == other.X() && m_y == other.Y() && m_z == other.Z() && m_w == other.W();
121 }
122
123 template <std::floating_point T>
124 template <std::floating_point U>
126 m_x += static_cast<T>(other.X());
127 m_y += static_cast<T>(other.Y());
128 m_z += static_cast<T>(other.Z());
129 m_w += static_cast<T>(other.W());
130
131 return *this;
132 }
133
134 template <std::floating_point T>
135 template <std::floating_point U>
137 m_x -= static_cast<T>(other.X());
138 m_y -= static_cast<T>(other.Y());
139 m_z -= static_cast<T>(other.Z());
140 m_w -= static_cast<T>(other.W());
141
142 return *this;
143 }
144
145 template <std::floating_point T>
146 template <std::floating_point U>
148 const T x = m_w * static_cast<T>(other.X()) + m_x * static_cast<T>(other.W()) +
149 m_y * static_cast<T>(other.Z()) - m_z * static_cast<T>(other.Y());
150 const T y = m_w * static_cast<T>(other.Y()) - m_x * static_cast<T>(other.Z()) +
151 m_y * static_cast<T>(other.W()) + m_z * static_cast<T>(other.X());
152 const T z = m_w * static_cast<T>(other.Z()) + m_x * static_cast<T>(other.Y()) -
153 m_y * static_cast<T>(other.X()) + m_z * static_cast<T>(other.W());
154 const T w = m_w * static_cast<T>(other.W()) - m_x * static_cast<T>(other.X()) -
155 m_y * static_cast<T>(other.Y()) - m_z * static_cast<T>(other.Z());
156
157 m_x = x;
158 m_y = y;
159 m_z = z;
160 m_w = w;
161
162 return *this;
163 }
164
165 template <std::floating_point T>
166 template <std::floating_point U>
168 m_x *= static_cast<T>(scalar);
169 m_y *= static_cast<T>(scalar);
170 m_z *= static_cast<T>(scalar);
171 m_w *= static_cast<T>(scalar);
172
173 return *this;
174 }
175
176 template <std::floating_point T>
177 template <std::floating_point U>
179 m_x /= static_cast<T>(scalar);
180 m_y /= static_cast<T>(scalar);
181 m_z /= static_cast<T>(scalar);
182 m_w /= static_cast<T>(scalar);
183
184 return *this;
185 }
186
187 template <std::floating_point T>
189 return *this;
190 }
191
192 template <std::floating_point T>
194 return Quaternion(-m_x, -m_y, -m_z, -m_w);
195 }
196
197 template <std::floating_point T>
198 constexpr T Quaternion<T>::LengthSquared() const {
199 return m_x * m_x + m_y * m_y + m_z * m_z + m_w * m_w;
200 }
201
202 template <std::floating_point T>
203 constexpr T Quaternion<T>::Length() const {
204 return std::sqrt(LengthSquared());
205 }
206
207 template <std::floating_point T>
209 const T length = Length();
210
211 if (length <= T{0}) {
212 return *this;
213 }
214
215 const T invLength = T{1} / length;
216 return Quaternion(m_x * invLength, m_y * invLength, m_z * invLength, m_w * invLength);
217 }
218
219 template <std::floating_point T>
220 constexpr void Quaternion<T>::Normalize() {
221 *this = Normalized();
222 }
223
224 template <std::floating_point T>
226 return Quaternion(-m_x, -m_y, -m_z, m_w);
227 }
228
229 template <std::floating_point T>
231 const T lengthSquared = LengthSquared();
232
233 if (lengthSquared <= T{0}) {
234 return Conjugate();
235 }
236
237 return Conjugate() / lengthSquared;
238 }
239
240 template <std::floating_point T>
241 constexpr Vec3<T> Quaternion<T>::RotateVector(const Vec3<T>& v) const {
242 const Vec3<T> q{m_x, m_y, m_z};
243
244 const Vec3<T> cross1{q[1] * v[2] - q[2] * v[1], q[2] * v[0] - q[0] * v[2], q[0] * v[1] - q[1] * v[0]};
245
246 const Vec3<T> cross2{q[1] * cross1[2] - q[2] * cross1[1], q[2] * cross1[0] - q[0] * cross1[2],
247 q[0] * cross1[1] - q[1] * cross1[0]};
248
249 return v + (cross1 * (T{2} * m_w)) + (cross2 * T{2});
250 }
251
252 template <std::floating_point T>
253 constexpr Vec3<T> Quaternion<T>::ToEuler() const {
254 return Vec3<T>{Pitch(), Yaw(), Roll()};
255 }
256
257 template <std::floating_point T>
258 constexpr T Quaternion<T>::Pitch() const {
259 const T sinPitch = T{2} * (m_w * m_x + m_y * m_z);
260 const T cosPitch = T{1} - T{2} * (m_x * m_x + m_y * m_y);
261
262 return std::atan2(sinPitch, cosPitch);
263 }
264
265 template <std::floating_point T>
266 constexpr T Quaternion<T>::Yaw() const {
267 const T sinYaw = T{2} * (m_w * m_y - m_z * m_x);
268
269 if (std::abs(sinYaw) >= T{1}) {
270 return std::copysign(std::numbers::pi_v<T> / T{2}, sinYaw);
271 }
272
273 return std::asin(sinYaw);
274 }
275
276 template <std::floating_point T>
277 constexpr T Quaternion<T>::Roll() const {
278 const T sinRoll = T{2} * (m_w * m_z + m_x * m_y);
279 const T cosRoll = T{1} - T{2} * (m_y * m_y + m_z * m_z);
280
281 return std::atan2(sinRoll, cosRoll);
282 }
283
284 template <std::floating_point T, std::floating_point U>
285 constexpr auto operator+(const Quaternion<T>& a, const Quaternion<U>& b) -> QuaternionCommon<T, U> {
286 using R = std::common_type_t<T, U>;
287
289 static_cast<R>(a.X()) + static_cast<R>(b.X()), static_cast<R>(a.Y()) + static_cast<R>(b.Y()),
290 static_cast<R>(a.Z()) + static_cast<R>(b.Z()), static_cast<R>(a.W()) + static_cast<R>(b.W()));
291 }
292
293 template <std::floating_point T, std::floating_point U>
294 constexpr auto operator-(const Quaternion<T>& a, const Quaternion<U>& b) -> QuaternionCommon<T, U> {
295 using R = std::common_type_t<T, U>;
296
298 static_cast<R>(a.X()) - static_cast<R>(b.X()), static_cast<R>(a.Y()) - static_cast<R>(b.Y()),
299 static_cast<R>(a.Z()) - static_cast<R>(b.Z()), static_cast<R>(a.W()) - static_cast<R>(b.W()));
300 }
301
302 template <std::floating_point T, std::floating_point U>
303 constexpr auto operator*(const Quaternion<T>& a, const Quaternion<U>& b) -> QuaternionCommon<T, U> {
304 using R = std::common_type_t<T, U>;
305
306 QuaternionCommon<T, U> result(static_cast<R>(a.X()), static_cast<R>(a.Y()), static_cast<R>(a.Z()),
307 static_cast<R>(a.W()));
308
309 result *= QuaternionCommon<T, U>(static_cast<R>(b.X()), static_cast<R>(b.Y()), static_cast<R>(b.Z()),
310 static_cast<R>(b.W()));
311
312 return result;
313 }
314
315 template <std::floating_point T, std::floating_point U>
316 constexpr auto operator*(const Quaternion<T>& q, U scalar) -> QuaternionCommon<T, U> {
317 using R = std::common_type_t<T, U>;
318
320 static_cast<R>(q.X()) * static_cast<R>(scalar), static_cast<R>(q.Y()) * static_cast<R>(scalar),
321 static_cast<R>(q.Z()) * static_cast<R>(scalar), static_cast<R>(q.W()) * static_cast<R>(scalar));
322 }
323
324 template <std::floating_point T, std::floating_point U>
325 constexpr auto operator*(U scalar, const Quaternion<T>& q) -> QuaternionCommon<T, U> {
326 return q * scalar;
327 }
328
329 template <std::floating_point T, std::floating_point U>
330 constexpr auto operator/(const Quaternion<T>& q, U scalar) -> QuaternionCommon<T, U> {
331 using R = std::common_type_t<T, U>;
332
334 static_cast<R>(q.X()) / static_cast<R>(scalar), static_cast<R>(q.Y()) / static_cast<R>(scalar),
335 static_cast<R>(q.Z()) / static_cast<R>(scalar), static_cast<R>(q.W()) / static_cast<R>(scalar));
336 }
337
338 template <std::floating_point T, std::floating_point U>
339 constexpr auto operator*(const Quaternion<T>& q, const Vec3<U>& v) -> Vec3<std::common_type_t<T, U>> {
340 using R = std::common_type_t<T, U>;
341
342 const Quaternion<R> qr(static_cast<R>(q.X()), static_cast<R>(q.Y()), static_cast<R>(q.Z()),
343 static_cast<R>(q.W()));
344 const Vec3<R> vr{static_cast<R>(v[0]), static_cast<R>(v[1]), static_cast<R>(v[2])};
345
346 return qr.RotateVector(vr);
347 }
348
349 template <std::floating_point T>
350 constexpr T Dot(const Quaternion<T>& a, const Quaternion<T>& b) {
351 return a.X() * b.X() + a.Y() * b.Y() + a.Z() * b.Z() + a.W() * b.W();
352 }
353
354 template <std::floating_point T>
355 constexpr Quaternion<T> Lerp(const Quaternion<T>& a, const Quaternion<T>& b, T t) {
356 return (a * (T{1} - t) + b * t).Normalized();
357 }
358
359 template <std::floating_point T>
360 constexpr Quaternion<T> Slerp(const Quaternion<T>& a, const Quaternion<T>& b, T t) {
361 Quaternion<T> end = b;
362 T cosOmega = Dot(a, b);
363
364 if (cosOmega < T{0}) {
365 cosOmega = -cosOmega;
366 end = -end;
367 }
368
369 constexpr T kEpsilon = static_cast<T>(1e-6);
370
371 if (cosOmega > T{1} - kEpsilon) {
372 return Lerp(a, end, t);
373 }
374
375 const T omega = std::acos(cosOmega);
376 const T sinOmega = std::sin(omega);
377
378 const T scaleA = std::sin((T{1} - t) * omega) / sinOmega;
379 const T scaleB = std::sin(t * omega) / sinOmega;
380
381 return (a * scaleA) + (end * scaleB);
382 }
383
384} // namespace Nexus
385
386template <std::floating_point T>
387struct std::formatter<Nexus::Quaternion<T>> {
388 std::formatter<T> underlying;
389
390 constexpr auto parse(std::format_parse_context& ctx) {
391 return underlying.parse(ctx);
392 }
393
394 auto format(const Nexus::Quaternion<T>& obj, std::format_context& ctx) const {
395 auto out = ctx.out();
396 out = std::format_to(out, "(");
397 out = underlying.format(obj.X(), ctx);
398 out = std::format_to(out, ", ");
399 out = underlying.format(obj.Y(), ctx);
400 out = std::format_to(out, ", ");
401 out = underlying.format(obj.Z(), ctx);
402 out = std::format_to(out, ", ");
403 out = underlying.format(obj.W(), ctx);
404 return std::format_to(out, ")");
405 }
406};
Definition Quaternion.cppm:18
static constexpr Quaternion FromAxisAngle(const Vec3< U > &axis, U angleRadians)
constexpr Quaternion()=default
constexpr T & Y()
Definition Quaternion.inl:73
constexpr T Yaw() const
Definition Quaternion.inl:266
constexpr Vec3< T > ToEuler() const
Definition Quaternion.inl:253
constexpr T & X()
Definition Quaternion.inl:63
constexpr Quaternion & operator*=(const Quaternion< U > &other)
constexpr void Normalize()
Definition Quaternion.inl:220
constexpr T & Z()
Definition Quaternion.inl:83
constexpr Quaternion Normalized() const
Definition Quaternion.inl:208
constexpr Quaternion Inverse() const
Definition Quaternion.inl:230
constexpr Quaternion operator+() const
Definition Quaternion.inl:188
constexpr T * Data()
Definition Quaternion.inl:103
constexpr T LengthSquared() const
Definition Quaternion.inl:198
constexpr Quaternion Conjugate() const
Definition Quaternion.inl:225
constexpr Quaternion & operator+=(const Quaternion< U > &other)
constexpr T Roll() const
Definition Quaternion.inl:277
static constexpr Quaternion Identity()
Definition Quaternion.inl:20
constexpr T Pitch() const
Definition Quaternion.inl:258
constexpr T & W()
Definition Quaternion.inl:93
constexpr Quaternion operator-() const
Definition Quaternion.inl:193
constexpr Vec3< T > RotateVector(const Vec3< T > &v) const
Definition Quaternion.inl:241
constexpr Quaternion & operator-=(const Quaternion< U > &other)
static constexpr size_type Size()
Definition Quaternion.inl:113
constexpr T Length() const
Definition Quaternion.inl:203
static constexpr Quaternion FromEuler(U pitch, U yaw, U roll)
constexpr bool operator==(const Quaternion< U > &other) const
Definition Quaternion.inl:119
constexpr Quaternion & operator/=(U scalar)
Definition Config.cppm:11
Vec< T, 3 > Vec3
Definition Vec.cppm:93
constexpr auto operator+(const Mat< T, RowCount, ColCount, Layout > &a, const Mat< U, RowCount, ColCount, Layout > &b) -> MatCommon< T, U, RowCount, ColCount, Layout >
Definition Mat.inl:289
std::size_t usize
Definition Types.cppm:25
constexpr auto operator*(const Mat< T, RowCount, ColCount, Layout > &mat, U scalar) -> MatCommon< T, U, RowCount, ColCount, Layout >
Definition Mat.inl:321
constexpr T Dot(const Quaternion< T > &a, const Quaternion< T > &b)
Definition Quaternion.inl:350
constexpr auto operator/(const Mat< T, RowCount, ColCount, Layout > &mat, U scalar) -> MatCommon< T, U, RowCount, ColCount, Layout >
Definition Mat.inl:343
constexpr auto operator-(const Mat< T, RowCount, ColCount, Layout > &a, const Mat< U, RowCount, ColCount, Layout > &b) -> MatCommon< T, U, RowCount, ColCount, Layout >
Definition Mat.inl:305
constexpr Quaternion< T > Lerp(const Quaternion< T > &a, const Quaternion< T > &b, T t)
Definition Quaternion.inl:355
constexpr Quaternion< T > Slerp(const Quaternion< T > &a, const Quaternion< T > &b, T t)
Definition Quaternion.inl:360
Quaternion< std::common_type_t< T, U > > QuaternionCommon
Definition Quaternion.cppm:102
constexpr auto parse(std::format_parse_context &ctx)
Definition Quaternion.inl:390
auto format(const Nexus::Quaternion< T > &obj, std::format_context &ctx) const
Definition Quaternion.inl:394
std::formatter< T > underlying
Definition Quaternion.inl:388