1#[cfg(feature = "approx")]
2use approx::{AbsDiffEq, RelativeEq, UlpsEq};
3use core::ops::{Mul, MulAssign};
4use glam::{Affine3A, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A};
5
6use crate::macros::glam_assert;
7
8#[repr(C)]
9#[derive(Debug, Default, Clone, Copy, PartialEq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
12pub struct Transform3A {
13 pub translation: Vec3A,
14 pub rotation: Quat,
15 pub scale: Vec3A,
16}
17
18impl Transform3A {
19 pub const ZERO: Self = Self {
24 translation: Vec3A::ZERO,
25 rotation: Quat::IDENTITY,
26 scale: Vec3A::ONE,
27 };
28
29 pub const IDENTITY: Self = Self {
33 translation: Vec3A::ZERO,
34 rotation: Quat::IDENTITY,
35 scale: Vec3A::ONE,
36 };
37
38 pub const NAN: Self = Self {
40 translation: Vec3A::NAN,
41 rotation: Quat::NAN,
42 scale: Vec3A::NAN,
43 };
44
45 #[inline]
47 #[must_use]
48 pub fn new(translation: Vec3, rotation: Quat, scale: Vec3) -> Self {
49 Self {
50 translation: translation.into(),
51 rotation,
52 scale: scale.into(),
53 }
54 }
55
56 #[inline]
59 #[must_use]
60 pub fn from_scale(scale: Vec3) -> Self {
61 Self {
62 translation: Vec3A::ZERO,
63 rotation: Quat::IDENTITY,
64 scale: scale.into(),
65 }
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn from_quat(rotation: Quat) -> Self {
72 Self {
73 translation: Vec3A::ZERO,
74 rotation,
75 scale: Vec3A::ONE,
76 }
77 }
78
79 #[inline]
82 #[must_use]
83 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
84 Self {
85 translation: Vec3A::ZERO,
86 rotation: Quat::from_axis_angle(axis, angle),
87 scale: Vec3A::ONE,
88 }
89 }
90
91 #[inline]
94 #[must_use]
95 pub fn from_rotation_x(angle: f32) -> Self {
96 Self {
97 translation: Vec3A::ZERO,
98 rotation: Quat::from_rotation_x(angle),
99 scale: Vec3A::ONE,
100 }
101 }
102
103 #[inline]
106 #[must_use]
107 pub fn from_rotation_y(angle: f32) -> Self {
108 Self {
109 translation: Vec3A::ZERO,
110 rotation: Quat::from_rotation_y(angle),
111 scale: Vec3A::ONE,
112 }
113 }
114
115 #[inline]
118 #[must_use]
119 pub fn from_rotation_z(angle: f32) -> Self {
120 Self {
121 translation: Vec3A::ZERO,
122 rotation: Quat::from_rotation_z(angle),
123 scale: Vec3A::ONE,
124 }
125 }
126
127 #[inline]
129 #[must_use]
130 pub fn from_translation(translation: Vec3) -> Self {
131 Self {
132 translation: translation.into(),
133 rotation: Quat::IDENTITY,
134 scale: Vec3A::ONE,
135 }
136 }
137
138 #[inline]
140 #[must_use]
141 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
142 Self {
143 translation: translation.into(),
144 rotation,
145 scale: Vec3A::ONE,
146 }
147 }
148
149 #[inline]
151 #[must_use]
152 pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
153 Self {
154 translation: translation.into(),
155 rotation,
156 scale: scale.into(),
157 }
158 }
159
160 #[inline]
164 #[must_use]
165 pub fn from_mat3(mat3: Mat3) -> Self {
166 Self::from_mat3_translation(mat3, Vec3::ZERO)
167 }
168
169 #[inline]
173 #[must_use]
174 pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
175 use super::math;
176 let det = mat3.determinant();
177 glam_assert!(det != 0.0);
178
179 let scale = Vec3::new(
180 mat3.x_axis.length() * math::signum(det),
181 mat3.y_axis.length(),
182 mat3.z_axis.length(),
183 );
184
185 glam_assert!(scale.cmpne(Vec3::ZERO).all());
186
187 let inv_scale = scale.recip();
188
189 let rotation = Quat::from_mat3(&Mat3::from_cols(
190 mat3.x_axis * inv_scale.x,
191 mat3.y_axis * inv_scale.y,
192 mat3.z_axis * inv_scale.z,
193 ));
194 Self {
195 translation: translation.into(),
196 rotation,
197 scale: scale.into(),
198 }
199 }
200
201 #[inline]
205 #[must_use]
206 pub fn from_mat4(mat4: Mat4) -> Self {
207 let translation = mat4.w_axis.truncate();
208 Self::from_mat3_translation(Mat3::from_mat4(mat4), translation)
209 }
210
211 #[inline]
213 #[must_use]
214 pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
215 (self.scale.into(), self.rotation, self.translation.into())
216 }
217
218 #[inline]
220 #[must_use]
221 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
222 let scale: Vec3 = self.scale.into();
223 let translation: Vec3 = self.translation.into();
224 self.rotation * (rhs * scale) + translation
225 }
226
227 #[inline]
229 #[must_use]
230 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
231 let scale: Vec3 = self.scale.into();
232 self.rotation * (rhs * scale)
233 }
234
235 #[inline]
237 #[must_use]
238 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
239 self.rotation * (rhs * self.scale) + self.translation
240 }
241
242 #[inline]
244 #[must_use]
245 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
246 self.rotation * (rhs * self.scale)
247 }
248
249 #[inline]
253 #[must_use]
254 pub fn is_finite(&self) -> bool {
255 self.translation.is_finite() && self.rotation.is_finite() && self.scale.is_finite()
256 }
257
258 #[inline]
260 #[must_use]
261 pub fn is_nan(&self) -> bool {
262 self.translation.is_nan() && self.rotation.is_nan() && self.scale.is_nan()
263 }
264
265 #[inline]
268 #[must_use]
269 pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
270 self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
271 && self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
272 && self.scale.abs_diff_eq(rhs.scale, max_abs_diff)
273 }
274
275 #[inline]
279 #[must_use]
280 pub fn inverse(&self) -> Self {
281 let rot = Mat3A::from_quat(self.rotation);
282 let mat_inv = Mat3A::from_cols(
283 rot.x_axis * self.scale.x,
284 rot.y_axis * self.scale.y,
285 rot.z_axis * self.scale.z,
286 )
287 .inverse();
288 let translation = -(mat_inv * self.translation);
289 Transform3A::from_mat3_translation(mat_inv.into(), translation.into())
290 }
291}
292
293impl From<Transform3A> for Mat4 {
294 #[inline]
295 fn from(t: Transform3A) -> Mat4 {
296 let mat3 = Mat3::from_quat(t.rotation);
297 Mat4::from_cols(
298 (mat3.x_axis * t.scale.x).extend(0.0),
299 (mat3.y_axis * t.scale.y).extend(0.0),
300 (mat3.z_axis * t.scale.z).extend(0.0),
301 t.translation.extend(1.0),
302 )
303 }
304}
305
306impl From<Transform3A> for Affine3A {
307 #[inline]
308 fn from(t: Transform3A) -> Affine3A {
309 Affine3A::from_scale_rotation_translation(t.scale.into(), t.rotation, t.translation.into())
310 }
311}
312
313impl Mul for Transform3A {
314 type Output = Transform3A;
315
316 #[inline]
317 fn mul(self, rhs: Self) -> Self::Output {
318 let rot1 = Mat3A::from_quat(self.rotation);
319 let mat1 = Mat3A::from_cols(
320 rot1.x_axis * self.scale.x,
321 rot1.y_axis * self.scale.y,
322 rot1.z_axis * self.scale.z,
323 );
324 let rot2 = Mat3A::from_quat(rhs.rotation);
325 let mat2 = Mat3A::from_cols(
326 rot2.x_axis * rhs.scale.x,
327 rot2.y_axis * rhs.scale.y,
328 rot2.z_axis * rhs.scale.z,
329 );
330 let translation = self.rotation * (self.scale * rhs.translation) + self.translation;
331 Transform3A::from_mat3_translation((mat1 * mat2).into(), translation.into())
332 }
333}
334
335impl MulAssign for Transform3A {
336 #[inline]
337 fn mul_assign(&mut self, rhs: Transform3A) {
338 *self = self.mul(rhs);
339 }
340}
341
342impl Mul<Mat4> for Transform3A {
343 type Output = Mat4;
344
345 #[inline]
346 fn mul(self, rhs: Mat4) -> Self::Output {
347 Mat4::from(self) * rhs
348 }
349}
350
351impl Mul<Transform3A> for Mat4 {
352 type Output = Mat4;
353
354 #[inline]
355 fn mul(self, rhs: Transform3A) -> Self::Output {
356 self * Mat4::from(rhs)
357 }
358}
359
360#[cfg(feature = "approx")]
361impl AbsDiffEq for Transform3A {
362 type Epsilon = <f32 as AbsDiffEq>::Epsilon;
363
364 #[inline]
365 fn default_epsilon() -> Self::Epsilon {
366 f32::default_epsilon()
367 }
368
369 #[inline]
370 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
371 self.translation.abs_diff_eq(other.translation, epsilon)
372 && self.rotation.abs_diff_eq(other.rotation, epsilon)
373 && self.scale.abs_diff_eq(other.scale, epsilon)
374 }
375}
376
377#[cfg(feature = "approx")]
378impl RelativeEq for Transform3A {
379 #[inline]
380 fn default_max_relative() -> Self::Epsilon {
381 f32::default_max_relative()
382 }
383
384 #[inline]
385 fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
386 self.translation.relative_eq(&other.translation, epsilon, max_relative)
387 && self.rotation.relative_eq(&other.rotation, epsilon, max_relative)
388 && self.scale.relative_eq(&other.scale, epsilon, max_relative)
389 }
390}
391
392#[cfg(feature = "approx")]
393impl UlpsEq for Transform3A {
394 #[inline]
395 fn default_max_ulps() -> u32 {
396 f32::default_max_ulps()
397 }
398
399 #[inline]
400 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
401 self.translation.ulps_eq(&other.translation, epsilon, max_ulps)
402 && self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps)
403 && self.scale.ulps_eq(&other.scale, epsilon, max_ulps)
404 }
405}
406
407#[cfg(test)]
408mod test {
409 use super::*;
410
411 #[test]
412 fn test_from_mat4() {
413 let scale = Vec3::new(0.5, 1.0, 2.0);
414 let rot = Quat::from_rotation_y(-0.6);
415 let pos = Vec3::new(1.0, -2.0, 3.0);
416 let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
417 let tran = Transform3A::from_mat4(mat);
418 assert!(Vec3::abs_diff_eq(tran.scale.into(), scale, 1e-6));
419 assert!(Quat::abs_diff_eq(tran.rotation, rot, 1e-6));
420 assert!(Vec3::abs_diff_eq(tran.translation.into(), pos, 1e-6));
421 }
422
423 #[test]
424 fn test_transform_point3() {
425 let scale = Vec3::new(1.0, 0.7, 0.5);
426 let rot = Quat::from_rotation_x(0.41);
427 let pos = Vec3::new(1.1, 2.1, -3.1);
428 let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
429 let tran = Transform3A::from_mat4(mat);
430
431 let point = Vec3::new(5.0, -5.0, 5.0);
432 let p1 = mat.project_point3(point);
433 let p2 = tran.transform_point3(point);
434 assert!(Vec3::abs_diff_eq(p1, p2, 1e-6));
435
436 let point = Vec3A::new(3.3, 4.4, 5.5);
437 let p1 = mat.project_point3a(point);
438 let p2 = tran.transform_point3a(point);
439 assert!(Vec3A::abs_diff_eq(p1, p2, 1e-6));
440 }
441
442 #[test]
443 fn test_transform_vec3() {
444 let scale = Vec3::new(2.0, 2.0, 0.35);
445 let rot = Quat::from_rotation_z(-0.2);
446 let pos = Vec3::new(-1.5, 2.5, 4.5);
447 let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
448 let tran = Transform3A::from_mat4(mat);
449
450 let vec = Vec3::new(1.0, 0.0, 0.7);
451 let v1 = mat.transform_vector3(vec);
452 let v2 = tran.transform_vector3(vec);
453 assert!(Vec3::abs_diff_eq(v1, v2, 1e-6));
454
455 let vec = Vec3A::new(-0.5, 1.0, 0.0);
456 let v1 = mat.transform_vector3a(vec);
457 let v2 = tran.transform_vector3a(vec);
458 assert!(Vec3A::abs_diff_eq(v1, v2, 1e-6));
459 }
460
461 #[test]
462 fn test_inverse() {
463 let scale = Vec3::new(2.0, 1.7, 0.35);
464 let rot = Quat::from_rotation_z(1.5) * Quat::from_rotation_x(1.0);
465 let pos = Vec3::new(1.99, 0.77, -1.55);
466 let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
467 let mat_inv = mat.inverse();
468 let tran1 = Transform3A::from_mat4(mat).inverse();
469 let tran2 = Transform3A::from_mat4(mat_inv);
470 assert!(Transform3A::abs_diff_eq(tran1, tran2, 1e-6));
471 }
472
473 #[test]
474 fn test_mat4_from() {
475 let scale = Vec3::new(3.1, 0.7, 1.11);
476 let rot = Quat::from_rotation_y(-2.0);
477 let pos = Vec3::new(3.0, 3.3, 3.33);
478 let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
479 let is = Transform3A::from_mat4(mat);
480 let mat2 = Mat4::from(is);
481 assert!(Mat4::abs_diff_eq(&mat, mat2, 1e-6));
482 }
483
484 #[test]
485 fn test_transform_mul() {
486 let scale1 = Vec3::new(1.1, 1.4, 1.7);
487 let rot1 = Quat::from_rotation_x(0.77);
488 let pos1 = Vec3::new(5.5, -6.6, 3.3);
489 let mat1 = Mat4::from_scale_rotation_translation(scale1, rot1, pos1);
490 let tran1 = Transform3A::from_scale_rotation_translation(scale1, rot1, pos1);
491
492 let scale2 = Vec3::new(0.3, 1.0, 0.7);
493 let rot2 = Quat::from_rotation_y(-0.44);
494 let pos2 = Vec3::new(-4.4, -2.2, -3.3);
495 let mat2 = Mat4::from_scale_rotation_translation(scale2, rot2, pos2);
496 let tran2 = Transform3A::from_scale_rotation_translation(scale2, rot2, pos2);
497
498 let mat = mat1 * mat2;
499 let tran = tran1 * tran2;
500 let tran_mat = Transform3A::from_mat4(mat);
501 assert!(Transform3A::abs_diff_eq(tran, tran_mat, 1e-6));
502 }
503}