glam_ext/f32_ext/
transform3a.rs

1use core::ops::{Mul, MulAssign};
2use glam::{Affine3A, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A};
3
4use crate::macros::glam_assert;
5
6#[repr(C)]
7#[derive(Debug, Default, Clone, Copy, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
10pub struct Transform3A {
11    pub translation: Vec3A,
12    pub rotation: Quat,
13    pub scale: Vec3A,
14}
15
16impl Transform3A {
17    /// The degenerate zero transform.
18    ///
19    /// This transforms any finite vector and point to zero.
20    /// The zero transform is non-invertible.
21    pub const ZERO: Self = Self {
22        translation: Vec3A::ZERO,
23        rotation: Quat::IDENTITY,
24        scale: Vec3A::ONE,
25    };
26
27    /// The identity transform.
28    ///
29    /// Multiplying a vector with this returns the same vector.
30    pub const IDENTITY: Self = Self {
31        translation: Vec3A::ZERO,
32        rotation: Quat::IDENTITY,
33        scale: Vec3A::ONE,
34    };
35
36    /// All NAN:s.
37    pub const NAN: Self = Self {
38        translation: Vec3A::NAN,
39        rotation: Quat::NAN,
40        scale: Vec3A::NAN,
41    };
42
43    /// Creates a new transform.
44    #[inline]
45    #[must_use]
46    pub fn new(translation: Vec3, rotation: Quat, scale: Vec3) -> Self {
47        Self {
48            translation: translation.into(),
49            rotation,
50            scale: scale.into(),
51        }
52    }
53
54    /// Creates an affine transform that changes scale.
55    /// Note that if any scale is zero the transform will be non-invertible.
56    #[inline]
57    #[must_use]
58    pub fn from_scale(scale: Vec3) -> Self {
59        Self {
60            translation: Vec3A::ZERO,
61            rotation: Quat::IDENTITY,
62            scale: scale.into(),
63        }
64    }
65
66    /// Creates a transform transform from the given `rotation` quaternion.
67    #[inline]
68    #[must_use]
69    pub fn from_quat(rotation: Quat) -> Self {
70        Self {
71            translation: Vec3A::ZERO,
72            rotation,
73            scale: Vec3A::ONE,
74        }
75    }
76
77    /// Creates a transform transform containing a 3D rotation around a normalized
78    /// rotation `axis` of `angle` (in radians).
79    #[inline]
80    #[must_use]
81    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
82        Self {
83            translation: Vec3A::ZERO,
84            rotation: Quat::from_axis_angle(axis, angle),
85            scale: Vec3A::ONE,
86        }
87    }
88
89    /// Creates a transform transform containing a 3D rotation around the x axis of
90    /// `angle` (in radians).
91    #[inline]
92    #[must_use]
93    pub fn from_rotation_x(angle: f32) -> Self {
94        Self {
95            translation: Vec3A::ZERO,
96            rotation: Quat::from_rotation_x(angle),
97            scale: Vec3A::ONE,
98        }
99    }
100
101    /// Creates a transform transform containing a 3D rotation around the y axis of
102    /// `angle` (in radians).
103    #[inline]
104    #[must_use]
105    pub fn from_rotation_y(angle: f32) -> Self {
106        Self {
107            translation: Vec3A::ZERO,
108            rotation: Quat::from_rotation_y(angle),
109            scale: Vec3A::ONE,
110        }
111    }
112
113    /// Creates a transform transform containing a 3D rotation around the z axis of
114    /// `angle` (in radians).
115    #[inline]
116    #[must_use]
117    pub fn from_rotation_z(angle: f32) -> Self {
118        Self {
119            translation: Vec3A::ZERO,
120            rotation: Quat::from_rotation_z(angle),
121            scale: Vec3A::ONE,
122        }
123    }
124
125    /// Creates a transform transformation from the given 3D `translation`.
126    #[inline]
127    #[must_use]
128    pub fn from_translation(translation: Vec3) -> Self {
129        Self {
130            translation: translation.into(),
131            rotation: Quat::IDENTITY,
132            scale: Vec3A::ONE,
133        }
134    }
135
136    /// Creates a transform from the given 3D `rotation` and `translation`.
137    #[inline]
138    #[must_use]
139    pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
140        Self {
141            translation: translation.into(),
142            rotation,
143            scale: Vec3A::ONE,
144        }
145    }
146
147    /// Creates a transform from the given 3D `scale`, `rotation` and `translation`.
148    #[inline]
149    #[must_use]
150    pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
151        Self {
152            translation: translation.into(),
153            rotation,
154            scale: scale.into(),
155        }
156    }
157
158    /// Creates a transform from a 3x3 matrix (expressing scale and rotation)
159    ///
160    /// Note if the input matrix is non-uniform or shear, the result transform will be ill-defined.
161    #[inline]
162    #[must_use]
163    pub fn from_mat3(mat3: Mat3) -> Self {
164        Self::from_mat3_translation(mat3, Vec3::ZERO)
165    }
166
167    /// Creates a transform from a 3x3 matrix (expressing scale and rotation)
168    ///
169    /// Note if the input matrix is non-uniform or shear, the result transform will be ill-defined.
170    #[inline]
171    #[must_use]
172    pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
173        use super::math;
174        let det = mat3.determinant();
175        glam_assert!(det != 0.0);
176
177        let scale = Vec3::new(
178            mat3.x_axis.length() * math::signum(det),
179            mat3.y_axis.length(),
180            mat3.z_axis.length(),
181        );
182
183        glam_assert!(scale.cmpne(Vec3::ZERO).all());
184
185        let inv_scale = scale.recip();
186
187        let rotation = Quat::from_mat3(&Mat3::from_cols(
188            mat3.x_axis * inv_scale.x,
189            mat3.y_axis * inv_scale.y,
190            mat3.z_axis * inv_scale.z,
191        ));
192        Self {
193            translation: translation.into(),
194            rotation,
195            scale: scale.into(),
196        }
197    }
198
199    /// Creates a transform from a 4x4 matrix.
200    ///
201    /// Note if the input matrix is non-uniform or shear, the result transform will be ill-defined.
202    #[inline]
203    #[must_use]
204    pub fn from_mat4(mat4: Mat4) -> Self {
205        let translation = mat4.w_axis.truncate();
206        Self::from_mat3_translation(Mat3::from_mat4(mat4), translation)
207    }
208
209    /// Extracts `scale`, `rotation` and `translation` from `self`.
210    #[inline]
211    #[must_use]
212    pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
213        (self.scale.into(), self.rotation, self.translation.into())
214    }
215
216    /// Transforms the given 3D points, applying scale, rotation and translation.
217    #[inline]
218    #[must_use]
219    pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
220        let scale: Vec3 = self.scale.into();
221        let translation: Vec3 = self.translation.into();
222        self.rotation * (rhs * scale) + translation
223    }
224
225    /// Transforms the given 3D vector, applying scale and rotation (but NOT translation).
226    #[inline]
227    #[must_use]
228    pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
229        let scale: Vec3 = self.scale.into();
230        self.rotation * (rhs * scale)
231    }
232
233    /// Transforms the given [`Vec3A`], applying scale, rotation and translation.
234    #[inline]
235    #[must_use]
236    pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
237        self.rotation * (rhs * self.scale) + self.translation
238    }
239
240    /// Transforms the given [`Vec3A`], applying scale and rotation (but NOT translation).
241    #[inline]
242    #[must_use]
243    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
244        self.rotation * (rhs * self.scale)
245    }
246
247    /// Returns `true` if, and only if, all elements are finite.
248    ///
249    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
250    #[inline]
251    #[must_use]
252    pub fn is_finite(&self) -> bool {
253        self.translation.is_finite() && self.rotation.is_finite() && self.scale.is_finite()
254    }
255
256    /// Returns `true` if any elements are `NaN`.
257    #[inline]
258    #[must_use]
259    pub fn is_nan(&self) -> bool {
260        self.translation.is_nan() && self.rotation.is_nan() && self.scale.is_nan()
261    }
262
263    /// Returns true if the absolute difference of all elements between `self` and `rhs`
264    /// is less than or equal to `max_abs_diff`.
265    #[inline]
266    #[must_use]
267    pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
268        self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
269            && self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
270            && self.scale.abs_diff_eq(rhs.scale, max_abs_diff)
271    }
272
273    /// Return the inverse of this transform.
274    ///
275    /// Note that if the transform is not invertible the result will be invalid.
276    #[inline]
277    #[must_use]
278    pub fn inverse(&self) -> Self {
279        let rot = Mat3A::from_quat(self.rotation);
280        let mat_inv = Mat3A::from_cols(
281            rot.x_axis * self.scale.x,
282            rot.y_axis * self.scale.y,
283            rot.z_axis * self.scale.z,
284        )
285        .inverse();
286        let translation = -(mat_inv * self.translation);
287        Transform3A::from_mat3_translation(mat_inv.into(), translation.into())
288    }
289}
290
291impl From<Transform3A> for Mat4 {
292    #[inline]
293    fn from(t: Transform3A) -> Mat4 {
294        let mat3 = Mat3::from_quat(t.rotation);
295        Mat4::from_cols(
296            (mat3.x_axis * t.scale.x).extend(0.0),
297            (mat3.y_axis * t.scale.y).extend(0.0),
298            (mat3.z_axis * t.scale.z).extend(0.0),
299            t.translation.extend(1.0),
300        )
301    }
302}
303
304impl From<Transform3A> for Affine3A {
305    #[inline]
306    fn from(t: Transform3A) -> Affine3A {
307        Affine3A::from_scale_rotation_translation(t.scale.into(), t.rotation, t.translation.into())
308    }
309}
310
311impl Mul for Transform3A {
312    type Output = Transform3A;
313
314    #[inline]
315    fn mul(self, rhs: Self) -> Self::Output {
316        let rot1 = Mat3A::from_quat(self.rotation);
317        let mat1 = Mat3A::from_cols(
318            rot1.x_axis * self.scale.x,
319            rot1.y_axis * self.scale.y,
320            rot1.z_axis * self.scale.z,
321        );
322        let rot2 = Mat3A::from_quat(rhs.rotation);
323        let mat2 = Mat3A::from_cols(
324            rot2.x_axis * rhs.scale.x,
325            rot2.y_axis * rhs.scale.y,
326            rot2.z_axis * rhs.scale.z,
327        );
328        let translation = self.rotation * (self.scale * rhs.translation) + self.translation;
329        Transform3A::from_mat3_translation((mat1 * mat2).into(), translation.into())
330    }
331}
332
333impl MulAssign for Transform3A {
334    #[inline]
335    fn mul_assign(&mut self, rhs: Transform3A) {
336        *self = self.mul(rhs);
337    }
338}
339
340impl Mul<Mat4> for Transform3A {
341    type Output = Mat4;
342
343    #[inline]
344    fn mul(self, rhs: Mat4) -> Self::Output {
345        Mat4::from(self) * rhs
346    }
347}
348
349impl Mul<Transform3A> for Mat4 {
350    type Output = Mat4;
351
352    #[inline]
353    fn mul(self, rhs: Transform3A) -> Self::Output {
354        self * Mat4::from(rhs)
355    }
356}
357
358#[cfg(test)]
359mod test {
360    use super::*;
361
362    #[test]
363    fn test_from_mat4() {
364        let scale = Vec3::new(0.5, 1.0, 2.0);
365        let rot = Quat::from_rotation_y(-0.6);
366        let pos = Vec3::new(1.0, -2.0, 3.0);
367        let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
368        let tran = Transform3A::from_mat4(mat);
369        assert!(Vec3::abs_diff_eq(tran.scale.into(), scale, 1e-6));
370        assert!(Quat::abs_diff_eq(tran.rotation, rot, 1e-6));
371        assert!(Vec3::abs_diff_eq(tran.translation.into(), pos, 1e-6));
372    }
373
374    #[test]
375    fn test_transform_point3() {
376        let scale = Vec3::new(1.0, 0.7, 0.5);
377        let rot = Quat::from_rotation_x(0.41);
378        let pos = Vec3::new(1.1, 2.1, -3.1);
379        let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
380        let tran = Transform3A::from_mat4(mat);
381
382        let point = Vec3::new(5.0, -5.0, 5.0);
383        let p1 = mat.project_point3(point);
384        let p2 = tran.transform_point3(point);
385        assert!(Vec3::abs_diff_eq(p1, p2, 1e-6));
386
387        let point = Vec3A::new(3.3, 4.4, 5.5);
388        let p1 = mat.project_point3a(point);
389        let p2 = tran.transform_point3a(point);
390        assert!(Vec3A::abs_diff_eq(p1, p2, 1e-6));
391    }
392
393    #[test]
394    fn test_transform_vec3() {
395        let scale = Vec3::new(2.0, 2.0, 0.35);
396        let rot = Quat::from_rotation_z(-0.2);
397        let pos = Vec3::new(-1.5, 2.5, 4.5);
398        let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
399        let tran = Transform3A::from_mat4(mat);
400
401        let vec = Vec3::new(1.0, 0.0, 0.7);
402        let v1 = mat.transform_vector3(vec);
403        let v2 = tran.transform_vector3(vec);
404        assert!(Vec3::abs_diff_eq(v1, v2, 1e-6));
405
406        let vec = Vec3A::new(-0.5, 1.0, 0.0);
407        let v1 = mat.transform_vector3a(vec);
408        let v2 = tran.transform_vector3a(vec);
409        assert!(Vec3A::abs_diff_eq(v1, v2, 1e-6));
410    }
411
412    #[test]
413    fn test_inverse() {
414        let scale = Vec3::new(2.0, 1.7, 0.35);
415        let rot = Quat::from_rotation_z(1.5) * Quat::from_rotation_x(1.0);
416        let pos = Vec3::new(1.99, 0.77, -1.55);
417        let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
418        let mat_inv = mat.inverse();
419        let tran1 = Transform3A::from_mat4(mat).inverse();
420        let tran2 = Transform3A::from_mat4(mat_inv);
421        assert!(Transform3A::abs_diff_eq(tran1, tran2, 1e-6));
422    }
423
424    #[test]
425    fn test_mat4_from() {
426        let scale = Vec3::new(3.1, 0.7, 1.11);
427        let rot = Quat::from_rotation_y(-2.0);
428        let pos = Vec3::new(3.0, 3.3, 3.33);
429        let mat = Mat4::from_scale_rotation_translation(scale, rot, pos);
430        let is = Transform3A::from_mat4(mat);
431        let mat2 = Mat4::from(is);
432        assert!(Mat4::abs_diff_eq(&mat, mat2, 1e-6));
433    }
434
435    #[test]
436    fn test_transform_mul() {
437        let scale1 = Vec3::new(1.1, 1.4, 1.7);
438        let rot1 = Quat::from_rotation_x(0.77);
439        let pos1 = Vec3::new(5.5, -6.6, 3.3);
440        let mat1 = Mat4::from_scale_rotation_translation(scale1, rot1, pos1);
441        let tran1 = Transform3A::from_scale_rotation_translation(scale1, rot1, pos1);
442
443        let scale2 = Vec3::new(0.3, 1.0, 0.7);
444        let rot2 = Quat::from_rotation_y(-0.44);
445        let pos2 = Vec3::new(-4.4, -2.2, -3.3);
446        let mat2 = Mat4::from_scale_rotation_translation(scale2, rot2, pos2);
447        let tran2 = Transform3A::from_scale_rotation_translation(scale2, rot2, pos2);
448
449        let mat = mat1 * mat2;
450        let tran = tran1 * tran2;
451        let tran_mat = Transform3A::from_mat4(mat);
452        assert!(Transform3A::abs_diff_eq(tran, tran_mat, 1e-6));
453    }
454}