A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
Quat.hh
1#pragma once
2
3#include "egg/math/Math.hh"
4#include "egg/math/Vector.hh"
5
6namespace Kinoko::EGG {
7
12struct Quatf {
13#ifdef BUILD_DEBUG
14 constexpr Quatf() : w(std::numeric_limits<f32>::signaling_NaN()) {}
15#else
16 constexpr Quatf() = default;
17#endif
18 constexpr Quatf(const Quatf &q) = default;
19 constexpr Quatf(f32 w_, const Vector3f &v_) : v(v_), w(w_) {}
20 constexpr Quatf(f32 w_, f32 x_, f32 y_, f32 z_) : v(x_, y_, z_), w(w_) {}
21 constexpr ~Quatf() = default;
22
23 constexpr Quatf &operator=(const Quatf &q) {
24 w = q.w;
25 v = q.v;
26
27 return *this;
28 }
29
30 [[nodiscard]] constexpr Quatf operator+(const Quatf &rhs) const {
31 return Quatf(w + rhs.w, v + rhs.v);
32 }
33
34 constexpr Quatf &operator+=(const Quatf &rhs) {
35 return *this = *this + rhs;
36 }
37
38 [[nodiscard]] constexpr Quatf operator*(const Vector3f &vec) const {
39 Vector3f cross = v.cross(vec);
40 Vector3f scale = vec * w;
41 return Quatf(-v.dot(vec), cross + scale);
42 }
43
44 [[nodiscard]] constexpr Quatf operator*(f32 scalar) const {
45 return Quatf(w * scalar, v * scalar);
46 }
47
48 constexpr Quatf &operator*=(f32 scalar) {
49 return *this = *this * scalar;
50 }
51
54 [[nodiscard]] constexpr Quatf operator*(const Quatf &rhs) const {
55 f32 _w = w * rhs.w - v.x * rhs.v.x - v.y * rhs.v.y - v.z * rhs.v.z;
56 f32 _x = v.y * rhs.v.z + (v.x * rhs.w + w * rhs.v.x) - v.z * rhs.v.y;
57 f32 _y = v.z * rhs.v.x + (v.y * rhs.w + w * rhs.v.y) - v.x * rhs.v.z;
58 f32 _z = v.x * rhs.v.y + (v.z * rhs.w + w * rhs.v.z) - v.y * rhs.v.x;
59
60 return Quatf(_w, _x, _y, _z);
61 }
62
63 constexpr Quatf &operator*=(const Quatf &q) {
64 return *this = *this * q;
65 }
66
67 [[nodiscard]] constexpr bool operator==(const Quatf &rhs) const {
68 return w == rhs.w && v == rhs.v;
69 }
70
71 [[nodiscard]] constexpr bool operator!=(const Quatf &rhs) const {
72 return !(*this == rhs);
73 }
74
76 [[nodiscard]] explicit operator std::string() const {
77 return std::format("[0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}] | [{}, {}, {}, {}]", f2u(v.x),
78 f2u(v.y), f2u(v.z), f2u(w), v.x, v.y, v.z, w);
79 }
80
83 constexpr void setRPY(const Vector3f &rpy) {
84 *this = FromRPY(rpy.x, rpy.y, rpy.z);
85 }
86
88 constexpr void setRPY(f32 r, f32 p, f32 y) {
89 const f32 cy = Mathf::cos(y * 0.5f);
90 const f32 cp = Mathf::cos(p * 0.5f);
91 const f32 cr = Mathf::cos(r * 0.5f);
92 const f32 sy = Mathf::sin(y * 0.5f);
93 const f32 sp = Mathf::sin(p * 0.5f);
94 const f32 sr = Mathf::sin(r * 0.5f);
95
96 w = cy * cp * cr + sy * sp * sr;
97 v.x = cy * cp * sr - sy * sp * cr;
98 v.y = cy * sp * cr + sy * cp * sr;
99 v.z = sy * cp * cr - cy * sp * sr;
100 }
101
104 constexpr void normalise() {
105 f32 len = squaredNorm() > std::numeric_limits<f32>::epsilon() ? norm() : 0.0f;
106
107 if (len != 0.0f) {
108 f32 inv = 1.0f / len;
109 w *= inv;
110 v *= inv;
111 }
112 }
113
116 constexpr void makeVectorRotation(const Vector3f &from, const Vector3f &to) {
117 f32 t0 = std::max(0.0f, (from.dot(to) + 1) * 2.0f);
118 t0 = Mathf::sqrt(t0);
119
120 if (t0 <= std::numeric_limits<f32>::epsilon()) {
121 *this = Quatf::ident;
122 } else {
123 const f32 inv = 1.0f / t0;
124 w = t0 * 0.5f;
125 v = from.cross(to) * inv;
126 }
127 }
128
130 [[nodiscard]] constexpr Quatf conjugate() const {
131 return Quatf(w, -v);
132 }
133
136 [[nodiscard]] constexpr Vector3f rotateVector(const Vector3f &vec) const {
137 Quatf conj = conjugate();
138 Quatf res = *this * vec;
139 Quatf ret;
140
141 ret.v.x = (res.v.y * conj.v.z + (res.v.x * conj.w + res.w * conj.v.x)) - res.v.z * conj.v.y;
142 ret.v.y = (res.v.z * conj.v.x + (res.v.y * conj.w + res.w * conj.v.y)) - res.v.x * conj.v.z;
143 ret.v.z = (res.v.x * conj.v.y + (res.v.z * conj.w + res.w * conj.v.z)) - res.v.y * conj.v.x;
144
145 return ret.v;
146 }
147
150 [[nodiscard]] constexpr Vector3f rotateVectorInv(const Vector3f &vec) const {
151 Quatf conj = conjugate();
152 Quatf res = conj * vec;
153 Quatf ret;
154
155 ret.v.x = (res.v.y * v.z + (res.v.x * w + res.w * v.x)) - res.v.z * v.y;
156 ret.v.y = (res.v.z * v.x + (res.v.y * w + res.w * v.y)) - res.v.x * v.z;
157 ret.v.z = (res.v.x * v.y + (res.v.z * w + res.w * v.z)) - res.v.y * v.x;
158
159 return ret.v;
160 }
161
165 [[nodiscard]] constexpr Quatf slerpTo(const Quatf &q1, f32 t) const {
166 f32 dot_ = std::max(-1.0f, std::min(1.0f, dot(q1)));
167 bool bDot = dot_ < 0.0f;
168 dot_ = Mathf::abs(dot_);
169
170 f32 acos = Mathf::acos(dot_);
171 f32 sin = Mathf::sin(acos);
172
173 f32 s;
174 if (Mathf::abs(sin) < 0.00001f) {
175 s = 1.0f - t;
176 } else {
177 f32 invSin = 1.0f / sin;
178 f32 tmp0 = t * acos;
179 s = invSin * Mathf::sin(acos - tmp0);
180 t = invSin * Mathf::sin(tmp0);
181 }
182
183 if (bDot) {
184 t = -t;
185 }
186
187 return Quatf(s * w + t * q1.w, s * v + t * q1.v);
188 }
189
192 [[nodiscard]] constexpr f32 squaredNorm() const {
193 return w * w + v.squaredLength();
194 }
195
196 [[nodiscard]] constexpr f32 norm() const {
197 return Mathf::sqrt(squaredNorm());
198 }
199
202 [[nodiscard]] constexpr f32 dot(const Quatf &q) const {
203 return w * q.w + v.dot(q.v);
204 }
205
208 constexpr void setAxisRotation(f32 angle, const EGG::Vector3f &axis) {
209 const f32 half_angle = angle * 0.5f;
210 const f32 c = Mathf::cos(half_angle);
211 const f32 s = Mathf::sin(half_angle);
212
213 w = c;
214 v = axis * s;
215 }
216
217 [[nodiscard]] constexpr Quatf multSwap(const Vector3f &vec) const {
218 f32 _w = -(v.dot(vec));
219 f32 _x = (w * vec.x + v.y * vec.z) - v.z * vec.y;
220 f32 _y = (w * vec.y + v.z * vec.x) - v.x * vec.z;
221 f32 _z = (w * vec.z + v.x * vec.y) - v.y * vec.x;
222
223 return Quatf(_w, _x, _y, _z);
224 }
225
226 [[nodiscard]] constexpr Quatf multSwap(const Quatf &q) const {
227 f32 _w = ((w * q.w - v.x * q.v.x) - v.y * q.v.y) - v.z * q.v.z;
228 f32 _x = (v.y * q.v.z + (v.x * q.w + w * q.v.x)) - v.z * q.v.y;
229 f32 _y = (v.z * q.v.x + (v.y * q.w + w * q.v.y)) - v.x * q.v.z;
230 f32 _z = (v.x * q.v.y + (v.z * q.w + w * q.v.z)) - v.y * q.v.x;
231
232 return Quatf(_w, _x, _y, _z);
233 }
234
235 void read(Stream &stream) {
236 v.read(stream);
237 w = stream.read_f32();
238 }
239
240 [[nodiscard]] static constexpr Quatf FromRPY(const EGG::Vector3f &rpy) {
241 Quatf ret;
242 ret.setRPY(rpy);
243 return ret;
244 }
245
247 [[nodiscard]] static constexpr Quatf FromRPY(f32 r, f32 p, f32 y) {
248 Quatf ret;
249 ret.setRPY(r, p, y);
250 return ret;
251 }
252
253 Vector3f v;
254 f32 w;
255
256 static const Quatf ident;
257};
258
259inline constexpr Quatf Quatf::ident = Quatf(1.0f, Vector3f::zero);
260
261} // namespace Kinoko::EGG
static constexpr f32 cos(f32 x)
Definition Math.hh:457
static constexpr f32 sin(f32 x)
Definition Math.hh:451
EGG core library.
Definition Archive.cc:6
A quaternion, used to represent 3D rotation.
Definition Quat.hh:12
constexpr Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
Definition Quat.hh:136
constexpr void setRPY(const Vector3f &rpy)
Sets roll, pitch, and yaw.
Definition Quat.hh:83
constexpr Quatf conjugate() const
Computes .
Definition Quat.hh:130
constexpr void normalise()
Scales the quaternion to a unit length.
Definition Quat.hh:104
constexpr void makeVectorRotation(const Vector3f &from, const Vector3f &to)
Captures rotation between two vectors.
Definition Quat.hh:116
constexpr f32 dot(const Quatf &q) const
Computes .
Definition Quat.hh:202
constexpr Quatf operator*(const Quatf &rhs) const
Definition Quat.hh:54
constexpr void setRPY(f32 r, f32 p, f32 y)
Helper function to avoid unnecessary Vector3f construction.
Definition Quat.hh:88
constexpr f32 squaredNorm() const
Computes .
Definition Quat.hh:192
constexpr Quatf slerpTo(const Quatf &q1, f32 t) const
Performs spherical linear interpolation.
Definition Quat.hh:165
static constexpr Quatf FromRPY(f32 r, f32 p, f32 y)
Helper function to avoid unnecessary Vector3f construction.
Definition Quat.hh:247
constexpr Vector3f rotateVectorInv(const Vector3f &vec) const
Rotates a vector on the inverse quat.
Definition Quat.hh:150
constexpr void setAxisRotation(f32 angle, const EGG::Vector3f &axis)
Set the quat given angle and axis.
Definition Quat.hh:208
A 3D float vector.
Definition Vector.hh:107
constexpr f32 squaredLength() const
The dot product between the vector and itself.
Definition Vector.hh:201
void read(Stream &stream)
Initializes a Vector3f by reading 12 bytes from the stream.
Definition Vector.hh:365
constexpr f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:206