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