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 pub const ZERO: Self = Self {
22 translation: Vec3A::ZERO,
23 rotation: Quat::IDENTITY,
24 scale: Vec3A::ONE,
25 };
26
27 pub const IDENTITY: Self = Self {
31 translation: Vec3A::ZERO,
32 rotation: Quat::IDENTITY,
33 scale: Vec3A::ONE,
34 };
35
36 pub const NAN: Self = Self {
38 translation: Vec3A::NAN,
39 rotation: Quat::NAN,
40 scale: Vec3A::NAN,
41 };
42
43 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
162 #[must_use]
163 pub fn from_mat3(mat3: Mat3) -> Self {
164 Self::from_mat3_translation(mat3, Vec3::ZERO)
165 }
166
167 #[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 #[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 #[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 #[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 #[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 #[inline]
235 #[must_use]
236 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
237 self.rotation * (rhs * self.scale) + self.translation
238 }
239
240 #[inline]
242 #[must_use]
243 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
244 self.rotation * (rhs * self.scale)
245 }
246
247 #[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 #[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 #[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 #[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}