Skip to main content

glam_ext/f32_ext/
transform3a.rs

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    /// The degenerate zero transform.
20    ///
21    /// This transforms any finite vector and point to zero.
22    /// The zero transform is non-invertible.
23    pub const ZERO: Self = Self {
24        translation: Vec3A::ZERO,
25        rotation: Quat::IDENTITY,
26        scale: Vec3A::ONE,
27    };
28
29    /// The identity transform.
30    ///
31    /// Multiplying a vector with this returns the same vector.
32    pub const IDENTITY: Self = Self {
33        translation: Vec3A::ZERO,
34        rotation: Quat::IDENTITY,
35        scale: Vec3A::ONE,
36    };
37
38    /// All NAN:s.
39    pub const NAN: Self = Self {
40        translation: Vec3A::NAN,
41        rotation: Quat::NAN,
42        scale: Vec3A::NAN,
43    };
44
45    /// Creates a new transform.
46    #[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    /// Creates a new transform.
57    #[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    /// Creates an affine transform that changes scale.
68    /// Note that if any scale is zero the transform will be non-invertible.
69    #[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    /// Creates a transform transform from the given `rotation` quaternion.
80    #[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    /// Creates a transform transform containing a 3D rotation around a normalized
91    /// rotation `axis` of `angle` (in radians).
92    #[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    /// Creates a transform transform containing a 3D rotation around the x axis of
103    /// `angle` (in radians).
104    #[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    /// Creates a transform transform containing a 3D rotation around the y axis of
115    /// `angle` (in radians).
116    #[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    /// Creates a transform transform containing a 3D rotation around the z axis of
127    /// `angle` (in radians).
128    #[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    /// Creates a transform transformation from the given 3D `translation`.
139    #[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    /// Creates a transform from the given 3D `rotation` and `translation`.
150    #[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    /// Creates a transform from the given 3D `scale`, `rotation` and `translation`.
161    #[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    /// Creates a transform from a 3x3 matrix (expressing scale and rotation)
172    ///
173    /// Note if the input matrix is non-uniform or shear, the result transform will be ill-defined.
174    #[inline]
175    #[must_use]
176    pub fn from_mat3(mat3: Mat3) -> Self {
177        Self::from_mat3_translation(mat3, Vec3::ZERO)
178    }
179
180    /// Creates a transform from a 3x3 matrix (expressing scale and rotation)
181    ///
182    /// Note if the input matrix is non-uniform or shear, the result transform will be ill-defined.
183    #[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    /// Creates a transform from a 4x4 matrix.
213    ///
214    /// Note if the input matrix is non-uniform or shear, the result transform will be ill-defined.
215    #[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    /// Extracts `scale`, `rotation` and `translation` from `self`.
223    #[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    /// Transforms the given 3D points, applying scale, rotation and translation.
230    #[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    /// Transforms the given 3D vector, applying scale and rotation (but NOT translation).
239    #[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    /// Transforms the given [`Vec3A`], applying scale, rotation and translation.
247    #[inline]
248    #[must_use]
249    pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
250        self.rotation * (rhs * self.scale) + self.translation
251    }
252
253    /// Transforms the given [`Vec3A`], applying scale and rotation (but NOT translation).
254    #[inline]
255    #[must_use]
256    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
257        self.rotation * (rhs * self.scale)
258    }
259
260    /// Returns `true` if, and only if, all elements are finite.
261    ///
262    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
263    #[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    /// Returns `true` if any elements are `NaN`.
270    #[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    /// Returns true if the absolute difference of all elements between `self` and `rhs`
277    /// is less than or equal to `max_abs_diff`.
278    #[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    /// Return the inverse of this transform.
287    ///
288    /// Note that if the transform is not invertible the result will be invalid.
289    #[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}