SuperDex Physics C++ API
Loading...
Searching...
No Matches
transform_rt_inl.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <mochi_core/utils/transform_rt.h> // for intellisense
20
21#include <cmath>
22#include <limits>
23
24namespace superdex {
25
26/************************************************************************************
27 TransformRT Inlines
28*/
29
30inline void TransformRT::WarnIfRotationNotNormalized() const {
31 // Log a warning in debug builds if the rotation is not unit length. This does not use
32 // MOCHI_ASSERT_VERBOSE because we don't want it to be fatal, especially in external code.
33#if MOCHI_ASSERT_VERBOSE_ENABLED && MOCHI_LOG_ENABLED
34 auto norm = Norm(_rotation);
35 if (!NearEqual(norm, 1_r, kQuaternionTol))
38 "TransformRT expects a unit length quaternion, but got [%g, %g, %g, %g] (magnitude %g).",
39 _rotation.data[0],
40 _rotation.data[1],
41 _rotation.data[2],
42 _rotation.data[3],
43 norm);
44 }
45#endif
46}
47
49 : _rotation(rotation), _translation(ToReal3(translation)) {
50 WarnIfRotationNotNormalized();
51}
52
53MOCHI_FORCE_INLINE TransformRT::TransformRT(Quaternion const& rotation, Real3 const& translation)
54 : _rotation(rotation), _translation(translation) {
55 WarnIfRotationNotNormalized();
56}
57
58MOCHI_FORCE_INLINE TransformRT::TransformRT(Quaternion const& rotation) : _rotation(rotation) {
59 WarnIfRotationNotNormalized();
60}
61
63 : _translation(ToReal3(translation)) {}
64
65MOCHI_FORCE_INLINE TransformRT::TransformRT(Real3 const& translation) : _translation(translation) {}
66
70
72 // Note: Implementation adapted from RTech's <graphics/vector.h>
73 // For a faster implementation, it might be worth measuring the
74 // performance compared to the raw assembly code described here:
75 // https://www.fd.cvut.cz/personal/voracsar/geometriepg/pgr020/matrix2quaternions.pdf
76 alignas(alignof(Vec4r)) real x[4];
77 alignas(alignof(Vec4r)) real y[4];
78 alignas(alignof(Vec4r)) real z[4];
79 VMatrix4x4r const& matColumns = mT;
80 Store(x, matColumns[0]);
81 Store(y, matColumns[1]);
82 Store(z, matColumns[2]);
83
84 alignas(alignof(Vec4r)) real q[4];
85 int k0 = 0, k1 = 0, k2 = 0, k3 = 0;
86 real s0 = 0_r, s1 = 0_r, s2 = 0_r;
87 if (x[0] + y[1] + z[2] > 0_r) {
88 k0 = 3;
89 k1 = 2;
90 k2 = 1;
91 k3 = 0;
92 s0 = 1.0_r;
93 s1 = 1.0_r;
94 s2 = 1.0_r;
95 } else if (x[0] > y[1] && x[0] > z[2]) {
96 k0 = 0;
97 k1 = 1;
98 k2 = 2;
99 k3 = 3;
100 s0 = 1.0_r;
101 s1 = -1.0_r;
102 s2 = -1.0_r;
103 } else if (y[1] > z[2]) {
104 k0 = 1;
105 k1 = 0;
106 k2 = 3;
107 k3 = 2;
108 s0 = -1.0_r;
109 s1 = 1.0_r;
110 s2 = -1.0_r;
111 } else {
112 k0 = 2;
113 k1 = 3;
114 k2 = 0;
115 k3 = 1;
116 s0 = -1.0_r;
117 s1 = -1.0_r;
118 s2 = 1.0_r;
119 }
120 real t = (s0 * x[0]) + (s1 * y[1]) + (s2 * z[2]) + 1.0_r;
121 real s = (1.0_r / std::sqrt(t)) * 0.5_r;
122 q[k0] = s * t;
123 q[k1] = (x[1] - s2 * y[0]) * s;
124 q[k2] = (z[0] - s1 * x[2]) * s;
125 q[k3] = (y[2] - s0 * z[1]) * s;
126
127 return TransformRT{Quaternion{q[0], q[1], q[2], q[3]}, matColumns[3]};
128}
129
133
135 return _rotation;
136}
137
139 _rotation = rotation;
140 WarnIfRotationNotNormalized();
141}
142
144 return ToSimd(_translation, 1_r);
145}
146
148 return _translation;
149}
150
152 _translation = ToReal3(translation);
153}
154
156 _translation = translation;
157}
158
160 return _rotation == rhs._rotation && _translation == rhs._translation;
161}
162
164 return !(*this == rhs);
165}
166
168 return TransformRT{
169 this->GetRotation() * rhs.GetRotation(),
170 this->VGetTranslation() + this->GetRotation() * rhs.VGetTranslation()};
171}
172
174 *this = (*this) * rhs;
175 return *this;
176}
177
179 return ToReal3(_rotation * ToSimd(pt, 0_r) + VGetTranslation());
180}
181
183 return ToReal3(_rotation * ToSimd(dir, 0_r));
184}
185
187 return ToReal3(Conjugate(_rotation) * (ToSimd(pt, 0_r) - VGetTranslation()));
188}
189
191 return ToReal3(Conjugate(_rotation) * ToSimd(dir, 0_r));
192}
193
195 return _rotation * ToSimdDirection(pt) + VGetTranslation();
196}
197
199 return _rotation * ToSimdDirection(dir);
200}
201
205
209
210/************************************************************************************
211 Utilities
212*/
213
215 Quaternion q = a.GetRotation();
216 return VMatrix4x4r{
217 q * Vec4r(1.0_r, 0.0_r, 0.0_r),
218 q * Vec4r(0.0_r, 1.0_r, 0.0_r),
219 q * Vec4r(0.0_r, 0.0_r, 1.0_r),
220 a.VGetTranslation()};
221}
222
226
227MOCHI_FORCE_INLINE bool NearEqual(TransformRT const& a, TransformRT const& b, Vec4r epsilon) {
228 return NearEqual(a.GetRotation(), b.GetRotation(), epsilon) &&
229 NearEqual(a.VGetTranslation(), b.VGetTranslation(), epsilon);
230}
231
232MOCHI_FORCE_INLINE bool NearEqual(TransformRT const& a, TransformRT const& b, real epsilon) {
233 return NearEqual(a, b, Vec4r{epsilon});
234}
235
239
241 return AllTrue(VIsFinite(a));
242}
243
245 Quaternion rotation = Conjugate(a.GetRotation());
246 Vec4r translation = rotation * ToSimdDirection(-a.VGetTranslation());
247 return TransformRT{rotation, translation};
248}
249
253
254MOCHI_FORCE_INLINE TransformRT Repivot(TransformRT const& transform, Real3 const& pivot) {
255 return TransformRT(
256 transform.GetRotation(),
257 transform.GetTranslation() - pivot + transform.GetRotation() * pivot);
258}
259
260inline TransformRT Interpolate(TransformRT const& a, TransformRT const& b, real t) {
261 auto trans = a.GetTranslation() * (1.0_r - t) + b.GetTranslation() * t;
262 auto rot = Slerp(a.GetRotation(), b.GetRotation(), t);
263 return TransformRT(rot, trans);
264}
265
266inline std::pair<Real3, TransformRT> DecomposeMatrixTransform(VMatrix4x4r const& matrixTransform) {
267 // Extract translation and scale using transpose to access columns
268 auto matrixT = Transpose4x4(matrixTransform);
269 auto translation = ToReal3(matrixT[3]);
270 auto scale = Real3{
271 Norm<3>(matrixT[0]), // Column 0
272 Norm<3>(matrixT[1]), // Column 1
273 Norm<3>(matrixT[2]) // Column 2
274 };
275
276 // Calculate 3x3 determinant to detect negative scaling (reflection)
277 auto determinant = Det3x3(matrixT);
278 if (determinant < 0_r) {
279 scale[0] = -scale[0]; // Flip the sign of any one axis.
280 }
281
282 // Normalize columns to extract rotation
283 matrixT[0] /= scale[0] + std::numeric_limits<real>::min();
284 matrixT[1] /= scale[1] + std::numeric_limits<real>::min();
285 matrixT[2] /= scale[2] + std::numeric_limits<real>::min();
286 auto rotation = QuaternionFromMatrix(Transpose3x3(matrixT));
287
288 return std::make_pair(scale, TransformRT{rotation, translation});
289}
290
291} // namespace superdex
static TransformRT Identity()
Real3 TransformPointInverse(Real3 const &pt) const
Quaternion const & GetRotation() const
Vec4r VGetTranslation() const
Real3 TransformDirectionInverse(Real3 const &dir) const
bool operator!=(TransformRT const &rhs) const
Real3 TransformDirection(Real3 const &dir) const
TransformRT operator*(TransformRT const &rhs) const
void SetTranslation(Real3 translation)
TransformRT & operator*=(TransformRT const &rhs)
bool operator==(TransformRT const &rhs) const
static TransformRT FromOrthoNormalTranspose(VMatrix4x4r const &mT)
Real3 TransformPoint(Real3 const &pt) const
static TransformRT FromOrthoNormal(VMatrix4x4r const &m)
void SetRotation(Quaternion const &rotation)
#define MOCHI_LOG_WARNING(...)
Definition log.h:43
#define MOCHI_UNLIKELY
#define MOCHI_FORCE_INLINE
Quaternion Slerp(Quaternion a, Quaternion b, real t)
Simd< T, N > VIsFinite(Simd< T, N > a)
Definition simd_inl.h:755
Simd< T, 4 > ToSimd(NdArray< T, 2 > const &v, T z=T(0), T w=T(0))
Definition vmatrix.h:413
T Norm(Simd< T, N > a)
Definition simd_inl.h:854
bool AllTrue(T const &a)
Definition basic_utils.h:60
V ToSimdDirection(V a)
Definition simd_inl.h:179
Real3 ToReal3(Simd< T, 4 > v)
Definition vmatrix.h:354
NdArray< Simd< T, 4 >, 3 > Transpose3x3(NdArray< Simd< T, 4 >, D0 > const &m)
Simd< real, 4 > Vec4r
Definition simd.h:206
std::pair< Real3, TransformRT > DecomposeMatrixTransform(VMatrix4x4r const &matrixTransform)
NdArray< Simd< real, 4 >, 4 > VMatrix4x4r
Definition vmatrix.h:55
Simd< T, N > Normalize(Simd< T, N > a)
Definition simd_inl.h:859
TransformRT Invert(TransformRT const &a)
VMatrix4x4r ToVMatrix4x4(TransformRT const &a)
NdArray< Simd< T, 4 >, 4 > Transpose4x4(NdArray< Simd< T, 4 >, 4 > const &m)
Quaternion Conjugate(Quaternion const &a)
NdArray< real, 3 > Real3
Definition nd_array.h:106
TransformRT Repivot(TransformRT const &transform, Real3 const &pivot)
VMatrix4x4r ToVMatrix4x4Transpose(TransformRT const &a)
void Store(T *ptr, Simd< T, N > a)
Definition simd_inl.h:213
TransformRT NormalizeRotation(TransformRT const &a)
TransformRT Interpolate(TransformRT const &a, TransformRT const &b, real t)
bool NearEqual(TransformRT const &a, TransformRT const &b, real epsilon=kDefaultNearEqualEpsilon< real >)
T Det3x3(NdArray< Simd< T, 4 >, N > const &A)
Quaternion QuaternionFromMatrix(VMatrix3x3r const &matrix, real eps=1e-3_r)
V ToSimdPoint(V a)
Definition simd_inl.h:174
bool IsFinite(TransformRT const &a)