1 // Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3 use crate::{
4 euler::{FromEuler, ToEuler},
5 f32::math,
6 swizzles::*,
7 DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
8 };
9 use core::fmt;
10 use core::iter::{Product, Sum};
11 use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
12
13 /// Creates a 4x4 matrix from four column vectors.
14 #[inline(always)]
15 #[must_use]
mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat416 pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 {
17 Mat4::from_cols(x_axis, y_axis, z_axis, w_axis)
18 }
19
20 /// A 4x4 column major matrix.
21 ///
22 /// This 4x4 matrix type features convenience methods for creating and using affine transforms and
23 /// perspective projections. If you are primarily dealing with 3D affine transformations
24 /// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix
25 /// for some affine operations.
26 ///
27 /// Affine transformations including 3D translation, rotation and scale can be created
28 /// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
29 /// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
30 ///
31 /// Orthographic projections can be created using the methods [`Self::orthographic_lh()`] for
32 /// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed
33 /// systems. The resulting matrix is also an affine transformation.
34 ///
35 /// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
36 /// are provided for performing affine transformations on 3D vectors and points. These
37 /// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
38 /// for vectors respectively. These methods assume that `Self` contains a valid affine
39 /// transform.
40 ///
41 /// Perspective projections can be created using methods such as
42 /// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and
43 /// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and
44 /// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and
45 /// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems.
46 ///
47 /// The resulting perspective project can be use to transform 3D vectors as points with
48 /// perspective correction using the [`Self::project_point3()`] convenience method.
49 #[derive(Clone, Copy)]
50 #[cfg_attr(
51 any(
52 not(any(feature = "scalar-math", target_arch = "spirv")),
53 feature = "cuda"
54 ),
55 repr(align(16))
56 )]
57 #[repr(C)]
58 pub struct Mat4 {
59 pub x_axis: Vec4,
60 pub y_axis: Vec4,
61 pub z_axis: Vec4,
62 pub w_axis: Vec4,
63 }
64
65 impl Mat4 {
66 /// A 4x4 matrix with all elements set to `0.0`.
67 pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO);
68
69 /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
70 pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W);
71
72 /// All NAN:s.
73 pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN);
74
75 #[allow(clippy::too_many_arguments)]
76 #[inline(always)]
77 #[must_use]
new( m00: f32, m01: f32, m02: f32, m03: f32, m10: f32, m11: f32, m12: f32, m13: f32, m20: f32, m21: f32, m22: f32, m23: f32, m30: f32, m31: f32, m32: f32, m33: f32, ) -> Self78 const fn new(
79 m00: f32,
80 m01: f32,
81 m02: f32,
82 m03: f32,
83 m10: f32,
84 m11: f32,
85 m12: f32,
86 m13: f32,
87 m20: f32,
88 m21: f32,
89 m22: f32,
90 m23: f32,
91 m30: f32,
92 m31: f32,
93 m32: f32,
94 m33: f32,
95 ) -> Self {
96 Self {
97 x_axis: Vec4::new(m00, m01, m02, m03),
98 y_axis: Vec4::new(m10, m11, m12, m13),
99 z_axis: Vec4::new(m20, m21, m22, m23),
100 w_axis: Vec4::new(m30, m31, m32, m33),
101 }
102 }
103
104 /// Creates a 4x4 matrix from four column vectors.
105 #[inline(always)]
106 #[must_use]
from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self107 pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self {
108 Self {
109 x_axis,
110 y_axis,
111 z_axis,
112 w_axis,
113 }
114 }
115
116 /// Creates a 4x4 matrix from a `[f32; 16]` array stored in column major order.
117 /// If your data is stored in row major you will need to `transpose` the returned
118 /// matrix.
119 #[inline]
120 #[must_use]
from_cols_array(m: &[f32; 16]) -> Self121 pub const fn from_cols_array(m: &[f32; 16]) -> Self {
122 Self::new(
123 m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13],
124 m[14], m[15],
125 )
126 }
127
128 /// Creates a `[f32; 16]` array storing data in column major order.
129 /// If you require data in row major order `transpose` the matrix first.
130 #[inline]
131 #[must_use]
to_cols_array(&self) -> [f32; 16]132 pub const fn to_cols_array(&self) -> [f32; 16] {
133 [
134 self.x_axis.x,
135 self.x_axis.y,
136 self.x_axis.z,
137 self.x_axis.w,
138 self.y_axis.x,
139 self.y_axis.y,
140 self.y_axis.z,
141 self.y_axis.w,
142 self.z_axis.x,
143 self.z_axis.y,
144 self.z_axis.z,
145 self.z_axis.w,
146 self.w_axis.x,
147 self.w_axis.y,
148 self.w_axis.z,
149 self.w_axis.w,
150 ]
151 }
152
153 /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 4D array stored in column major order.
154 /// If your data is in row major order you will need to `transpose` the returned
155 /// matrix.
156 #[inline]
157 #[must_use]
from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self158 pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self {
159 Self::from_cols(
160 Vec4::from_array(m[0]),
161 Vec4::from_array(m[1]),
162 Vec4::from_array(m[2]),
163 Vec4::from_array(m[3]),
164 )
165 }
166
167 /// Creates a `[[f32; 4]; 4]` 4D array storing data in column major order.
168 /// If you require data in row major order `transpose` the matrix first.
169 #[inline]
170 #[must_use]
to_cols_array_2d(&self) -> [[f32; 4]; 4]171 pub const fn to_cols_array_2d(&self) -> [[f32; 4]; 4] {
172 [
173 self.x_axis.to_array(),
174 self.y_axis.to_array(),
175 self.z_axis.to_array(),
176 self.w_axis.to_array(),
177 ]
178 }
179
180 /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0.
181 #[doc(alias = "scale")]
182 #[inline]
183 #[must_use]
from_diagonal(diagonal: Vec4) -> Self184 pub const fn from_diagonal(diagonal: Vec4) -> Self {
185 Self::new(
186 diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0,
187 0.0, 0.0, diagonal.w,
188 )
189 }
190
191 #[inline]
192 #[must_use]
quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4)193 fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) {
194 glam_assert!(rotation.is_normalized());
195
196 let (x, y, z, w) = rotation.into();
197 let x2 = x + x;
198 let y2 = y + y;
199 let z2 = z + z;
200 let xx = x * x2;
201 let xy = x * y2;
202 let xz = x * z2;
203 let yy = y * y2;
204 let yz = y * z2;
205 let zz = z * z2;
206 let wx = w * x2;
207 let wy = w * y2;
208 let wz = w * z2;
209
210 let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
211 let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
212 let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
213 (x_axis, y_axis, z_axis)
214 }
215
216 /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and
217 /// `translation`.
218 ///
219 /// The resulting matrix can be used to transform 3D points and vectors. See
220 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
221 ///
222 /// # Panics
223 ///
224 /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
225 #[inline]
226 #[must_use]
from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self227 pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
228 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
229 Self::from_cols(
230 x_axis.mul(scale.x),
231 y_axis.mul(scale.y),
232 z_axis.mul(scale.z),
233 Vec4::from((translation, 1.0)),
234 )
235 }
236
237 /// Creates an affine transformation matrix from the given 3D `translation`.
238 ///
239 /// The resulting matrix can be used to transform 3D points and vectors. See
240 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
241 ///
242 /// # Panics
243 ///
244 /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
245 #[inline]
246 #[must_use]
from_rotation_translation(rotation: Quat, translation: Vec3) -> Self247 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
248 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
249 Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0)))
250 }
251
252 /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is
253 /// expected to be a 3D affine transformation matrix otherwise the output will be invalid.
254 ///
255 /// # Panics
256 ///
257 /// Will panic if the determinant of `self` is zero or if the resulting scale vector
258 /// contains any zero elements when `glam_assert` is enabled.
259 #[inline]
260 #[must_use]
to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3)261 pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
262 let det = self.determinant();
263 glam_assert!(det != 0.0);
264
265 let scale = Vec3::new(
266 self.x_axis.length() * math::signum(det),
267 self.y_axis.length(),
268 self.z_axis.length(),
269 );
270
271 glam_assert!(scale.cmpne(Vec3::ZERO).all());
272
273 let inv_scale = scale.recip();
274
275 let rotation = Quat::from_rotation_axes(
276 self.x_axis.mul(inv_scale.x).xyz(),
277 self.y_axis.mul(inv_scale.y).xyz(),
278 self.z_axis.mul(inv_scale.z).xyz(),
279 );
280
281 let translation = self.w_axis.xyz();
282
283 (scale, rotation, translation)
284 }
285
286 /// Creates an affine transformation matrix from the given `rotation` quaternion.
287 ///
288 /// The resulting matrix can be used to transform 3D points and vectors. See
289 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
290 ///
291 /// # Panics
292 ///
293 /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
294 #[inline]
295 #[must_use]
from_quat(rotation: Quat) -> Self296 pub fn from_quat(rotation: Quat) -> Self {
297 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
298 Self::from_cols(x_axis, y_axis, z_axis, Vec4::W)
299 }
300
301 /// Creates an affine transformation matrix from the given 3x3 linear transformation
302 /// matrix.
303 ///
304 /// The resulting matrix can be used to transform 3D points and vectors. See
305 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
306 #[inline]
307 #[must_use]
from_mat3(m: Mat3) -> Self308 pub fn from_mat3(m: Mat3) -> Self {
309 Self::from_cols(
310 Vec4::from((m.x_axis, 0.0)),
311 Vec4::from((m.y_axis, 0.0)),
312 Vec4::from((m.z_axis, 0.0)),
313 Vec4::W,
314 )
315 }
316
317 /// Creates an affine transformation matrics from a 3x3 matrix (expressing scale, shear and
318 /// rotation) and a translation vector.
319 ///
320 /// Equivalent to `Mat4::from_translation(translation) * Mat4::from_mat3(mat3)`
321 #[inline]
322 #[must_use]
from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self323 pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
324 Self::from_cols(
325 Vec4::from((mat3.x_axis, 0.0)),
326 Vec4::from((mat3.y_axis, 0.0)),
327 Vec4::from((mat3.z_axis, 0.0)),
328 Vec4::from((translation, 1.0)),
329 )
330 }
331
332 /// Creates an affine transformation matrix from the given 3x3 linear transformation
333 /// matrix.
334 ///
335 /// The resulting matrix can be used to transform 3D points and vectors. See
336 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
337 #[inline]
338 #[must_use]
from_mat3a(m: Mat3A) -> Self339 pub fn from_mat3a(m: Mat3A) -> Self {
340 Self::from_cols(
341 Vec4::from((m.x_axis, 0.0)),
342 Vec4::from((m.y_axis, 0.0)),
343 Vec4::from((m.z_axis, 0.0)),
344 Vec4::W,
345 )
346 }
347
348 /// Creates an affine transformation matrix from the given 3D `translation`.
349 ///
350 /// The resulting matrix can be used to transform 3D points and vectors. See
351 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
352 #[inline]
353 #[must_use]
from_translation(translation: Vec3) -> Self354 pub fn from_translation(translation: Vec3) -> Self {
355 Self::from_cols(
356 Vec4::X,
357 Vec4::Y,
358 Vec4::Z,
359 Vec4::new(translation.x, translation.y, translation.z, 1.0),
360 )
361 }
362
363 /// Creates an affine transformation matrix containing a 3D rotation around a normalized
364 /// rotation `axis` of `angle` (in radians).
365 ///
366 /// The resulting matrix can be used to transform 3D points and vectors. See
367 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
368 ///
369 /// # Panics
370 ///
371 /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
372 #[inline]
373 #[must_use]
from_axis_angle(axis: Vec3, angle: f32) -> Self374 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
375 glam_assert!(axis.is_normalized());
376
377 let (sin, cos) = math::sin_cos(angle);
378 let axis_sin = axis.mul(sin);
379 let axis_sq = axis.mul(axis);
380 let omc = 1.0 - cos;
381 let xyomc = axis.x * axis.y * omc;
382 let xzomc = axis.x * axis.z * omc;
383 let yzomc = axis.y * axis.z * omc;
384 Self::from_cols(
385 Vec4::new(
386 axis_sq.x * omc + cos,
387 xyomc + axis_sin.z,
388 xzomc - axis_sin.y,
389 0.0,
390 ),
391 Vec4::new(
392 xyomc - axis_sin.z,
393 axis_sq.y * omc + cos,
394 yzomc + axis_sin.x,
395 0.0,
396 ),
397 Vec4::new(
398 xzomc + axis_sin.y,
399 yzomc - axis_sin.x,
400 axis_sq.z * omc + cos,
401 0.0,
402 ),
403 Vec4::W,
404 )
405 }
406
407 /// Creates a affine transformation matrix containing a rotation from the given euler
408 /// rotation sequence and angles (in radians).
409 ///
410 /// The resulting matrix can be used to transform 3D points and vectors. See
411 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
412 #[inline]
413 #[must_use]
from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self414 pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
415 Self::from_euler_angles(order, a, b, c)
416 }
417
418 /// Extract Euler angles with the given Euler rotation order.
419 ///
420 /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
421 /// then the resulting Euler angles will be ill-defined.
422 ///
423 /// # Panics
424 ///
425 /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
426 /// `glam_assert` is enabled.
427 #[inline]
428 #[must_use]
to_euler(&self, order: EulerRot) -> (f32, f32, f32)429 pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
430 glam_assert!(
431 self.x_axis.xyz().is_normalized()
432 && self.y_axis.xyz().is_normalized()
433 && self.z_axis.xyz().is_normalized()
434 );
435 self.to_euler_angles(order)
436 }
437
438 /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
439 /// `angle` (in radians).
440 ///
441 /// The resulting matrix can be used to transform 3D points and vectors. See
442 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
443 #[inline]
444 #[must_use]
from_rotation_x(angle: f32) -> Self445 pub fn from_rotation_x(angle: f32) -> Self {
446 let (sina, cosa) = math::sin_cos(angle);
447 Self::from_cols(
448 Vec4::X,
449 Vec4::new(0.0, cosa, sina, 0.0),
450 Vec4::new(0.0, -sina, cosa, 0.0),
451 Vec4::W,
452 )
453 }
454
455 /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
456 /// `angle` (in radians).
457 ///
458 /// The resulting matrix can be used to transform 3D points and vectors. See
459 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
460 #[inline]
461 #[must_use]
from_rotation_y(angle: f32) -> Self462 pub fn from_rotation_y(angle: f32) -> Self {
463 let (sina, cosa) = math::sin_cos(angle);
464 Self::from_cols(
465 Vec4::new(cosa, 0.0, -sina, 0.0),
466 Vec4::Y,
467 Vec4::new(sina, 0.0, cosa, 0.0),
468 Vec4::W,
469 )
470 }
471
472 /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
473 /// `angle` (in radians).
474 ///
475 /// The resulting matrix can be used to transform 3D points and vectors. See
476 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
477 #[inline]
478 #[must_use]
from_rotation_z(angle: f32) -> Self479 pub fn from_rotation_z(angle: f32) -> Self {
480 let (sina, cosa) = math::sin_cos(angle);
481 Self::from_cols(
482 Vec4::new(cosa, sina, 0.0, 0.0),
483 Vec4::new(-sina, cosa, 0.0, 0.0),
484 Vec4::Z,
485 Vec4::W,
486 )
487 }
488
489 /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
490 ///
491 /// The resulting matrix can be used to transform 3D points and vectors. See
492 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
493 ///
494 /// # Panics
495 ///
496 /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
497 #[inline]
498 #[must_use]
from_scale(scale: Vec3) -> Self499 pub fn from_scale(scale: Vec3) -> Self {
500 // Do not panic as long as any component is non-zero
501 glam_assert!(scale.cmpne(Vec3::ZERO).any());
502
503 Self::from_cols(
504 Vec4::new(scale.x, 0.0, 0.0, 0.0),
505 Vec4::new(0.0, scale.y, 0.0, 0.0),
506 Vec4::new(0.0, 0.0, scale.z, 0.0),
507 Vec4::W,
508 )
509 }
510
511 /// Creates a 4x4 matrix from the first 16 values in `slice`.
512 ///
513 /// # Panics
514 ///
515 /// Panics if `slice` is less than 16 elements long.
516 #[inline]
517 #[must_use]
from_cols_slice(slice: &[f32]) -> Self518 pub const fn from_cols_slice(slice: &[f32]) -> Self {
519 Self::new(
520 slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
521 slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
522 )
523 }
524
525 /// Writes the columns of `self` to the first 16 elements in `slice`.
526 ///
527 /// # Panics
528 ///
529 /// Panics if `slice` is less than 16 elements long.
530 #[inline]
write_cols_to_slice(self, slice: &mut [f32])531 pub fn write_cols_to_slice(self, slice: &mut [f32]) {
532 slice[0] = self.x_axis.x;
533 slice[1] = self.x_axis.y;
534 slice[2] = self.x_axis.z;
535 slice[3] = self.x_axis.w;
536 slice[4] = self.y_axis.x;
537 slice[5] = self.y_axis.y;
538 slice[6] = self.y_axis.z;
539 slice[7] = self.y_axis.w;
540 slice[8] = self.z_axis.x;
541 slice[9] = self.z_axis.y;
542 slice[10] = self.z_axis.z;
543 slice[11] = self.z_axis.w;
544 slice[12] = self.w_axis.x;
545 slice[13] = self.w_axis.y;
546 slice[14] = self.w_axis.z;
547 slice[15] = self.w_axis.w;
548 }
549
550 /// Returns the matrix column for the given `index`.
551 ///
552 /// # Panics
553 ///
554 /// Panics if `index` is greater than 3.
555 #[inline]
556 #[must_use]
col(&self, index: usize) -> Vec4557 pub fn col(&self, index: usize) -> Vec4 {
558 match index {
559 0 => self.x_axis,
560 1 => self.y_axis,
561 2 => self.z_axis,
562 3 => self.w_axis,
563 _ => panic!("index out of bounds"),
564 }
565 }
566
567 /// Returns a mutable reference to the matrix column for the given `index`.
568 ///
569 /// # Panics
570 ///
571 /// Panics if `index` is greater than 3.
572 #[inline]
col_mut(&mut self, index: usize) -> &mut Vec4573 pub fn col_mut(&mut self, index: usize) -> &mut Vec4 {
574 match index {
575 0 => &mut self.x_axis,
576 1 => &mut self.y_axis,
577 2 => &mut self.z_axis,
578 3 => &mut self.w_axis,
579 _ => panic!("index out of bounds"),
580 }
581 }
582
583 /// Returns the matrix row for the given `index`.
584 ///
585 /// # Panics
586 ///
587 /// Panics if `index` is greater than 3.
588 #[inline]
589 #[must_use]
row(&self, index: usize) -> Vec4590 pub fn row(&self, index: usize) -> Vec4 {
591 match index {
592 0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
593 1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
594 2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
595 3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
596 _ => panic!("index out of bounds"),
597 }
598 }
599
600 /// Returns `true` if, and only if, all elements are finite.
601 /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
602 #[inline]
603 #[must_use]
is_finite(&self) -> bool604 pub fn is_finite(&self) -> bool {
605 self.x_axis.is_finite()
606 && self.y_axis.is_finite()
607 && self.z_axis.is_finite()
608 && self.w_axis.is_finite()
609 }
610
611 /// Returns `true` if any elements are `NaN`.
612 #[inline]
613 #[must_use]
is_nan(&self) -> bool614 pub fn is_nan(&self) -> bool {
615 self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
616 }
617
618 /// Returns the transpose of `self`.
619 #[inline]
620 #[must_use]
transpose(&self) -> Self621 pub fn transpose(&self) -> Self {
622 Self {
623 x_axis: Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
624 y_axis: Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
625 z_axis: Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
626 w_axis: Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
627 }
628 }
629
630 /// Returns the determinant of `self`.
631 #[must_use]
determinant(&self) -> f32632 pub fn determinant(&self) -> f32 {
633 let (m00, m01, m02, m03) = self.x_axis.into();
634 let (m10, m11, m12, m13) = self.y_axis.into();
635 let (m20, m21, m22, m23) = self.z_axis.into();
636 let (m30, m31, m32, m33) = self.w_axis.into();
637
638 let a2323 = m22 * m33 - m23 * m32;
639 let a1323 = m21 * m33 - m23 * m31;
640 let a1223 = m21 * m32 - m22 * m31;
641 let a0323 = m20 * m33 - m23 * m30;
642 let a0223 = m20 * m32 - m22 * m30;
643 let a0123 = m20 * m31 - m21 * m30;
644
645 m00 * (m11 * a2323 - m12 * a1323 + m13 * a1223)
646 - m01 * (m10 * a2323 - m12 * a0323 + m13 * a0223)
647 + m02 * (m10 * a1323 - m11 * a0323 + m13 * a0123)
648 - m03 * (m10 * a1223 - m11 * a0223 + m12 * a0123)
649 }
650
651 /// Returns the inverse of `self`.
652 ///
653 /// If the matrix is not invertible the returned matrix will be invalid.
654 ///
655 /// # Panics
656 ///
657 /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
658 #[must_use]
inverse(&self) -> Self659 pub fn inverse(&self) -> Self {
660 let (m00, m01, m02, m03) = self.x_axis.into();
661 let (m10, m11, m12, m13) = self.y_axis.into();
662 let (m20, m21, m22, m23) = self.z_axis.into();
663 let (m30, m31, m32, m33) = self.w_axis.into();
664
665 let coef00 = m22 * m33 - m32 * m23;
666 let coef02 = m12 * m33 - m32 * m13;
667 let coef03 = m12 * m23 - m22 * m13;
668
669 let coef04 = m21 * m33 - m31 * m23;
670 let coef06 = m11 * m33 - m31 * m13;
671 let coef07 = m11 * m23 - m21 * m13;
672
673 let coef08 = m21 * m32 - m31 * m22;
674 let coef10 = m11 * m32 - m31 * m12;
675 let coef11 = m11 * m22 - m21 * m12;
676
677 let coef12 = m20 * m33 - m30 * m23;
678 let coef14 = m10 * m33 - m30 * m13;
679 let coef15 = m10 * m23 - m20 * m13;
680
681 let coef16 = m20 * m32 - m30 * m22;
682 let coef18 = m10 * m32 - m30 * m12;
683 let coef19 = m10 * m22 - m20 * m12;
684
685 let coef20 = m20 * m31 - m30 * m21;
686 let coef22 = m10 * m31 - m30 * m11;
687 let coef23 = m10 * m21 - m20 * m11;
688
689 let fac0 = Vec4::new(coef00, coef00, coef02, coef03);
690 let fac1 = Vec4::new(coef04, coef04, coef06, coef07);
691 let fac2 = Vec4::new(coef08, coef08, coef10, coef11);
692 let fac3 = Vec4::new(coef12, coef12, coef14, coef15);
693 let fac4 = Vec4::new(coef16, coef16, coef18, coef19);
694 let fac5 = Vec4::new(coef20, coef20, coef22, coef23);
695
696 let vec0 = Vec4::new(m10, m00, m00, m00);
697 let vec1 = Vec4::new(m11, m01, m01, m01);
698 let vec2 = Vec4::new(m12, m02, m02, m02);
699 let vec3 = Vec4::new(m13, m03, m03, m03);
700
701 let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2));
702 let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4));
703 let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5));
704 let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5));
705
706 let sign_a = Vec4::new(1.0, -1.0, 1.0, -1.0);
707 let sign_b = Vec4::new(-1.0, 1.0, -1.0, 1.0);
708
709 let inverse = Self::from_cols(
710 inv0.mul(sign_a),
711 inv1.mul(sign_b),
712 inv2.mul(sign_a),
713 inv3.mul(sign_b),
714 );
715
716 let col0 = Vec4::new(
717 inverse.x_axis.x,
718 inverse.y_axis.x,
719 inverse.z_axis.x,
720 inverse.w_axis.x,
721 );
722
723 let dot0 = self.x_axis.mul(col0);
724 let dot1 = dot0.x + dot0.y + dot0.z + dot0.w;
725
726 glam_assert!(dot1 != 0.0);
727
728 let rcp_det = dot1.recip();
729 inverse.mul(rcp_det)
730 }
731
732 /// Creates a left-handed view matrix using a camera position, a facing direction and an up
733 /// direction
734 ///
735 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
736 ///
737 /// # Panics
738 ///
739 /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
740 #[inline]
741 #[must_use]
look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self742 pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
743 Self::look_to_rh(eye, -dir, up)
744 }
745
746 /// Creates a right-handed view matrix using a camera position, a facing direction, and an up
747 /// direction.
748 ///
749 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
750 ///
751 /// # Panics
752 ///
753 /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
754 #[inline]
755 #[must_use]
look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self756 pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
757 glam_assert!(dir.is_normalized());
758 glam_assert!(up.is_normalized());
759 let f = dir;
760 let s = f.cross(up).normalize();
761 let u = s.cross(f);
762
763 Self::from_cols(
764 Vec4::new(s.x, u.x, -f.x, 0.0),
765 Vec4::new(s.y, u.y, -f.y, 0.0),
766 Vec4::new(s.z, u.z, -f.z, 0.0),
767 Vec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
768 )
769 }
770
771 /// Creates a left-handed view matrix using a camera position, a focal points and an up
772 /// direction.
773 ///
774 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
775 ///
776 /// # Panics
777 ///
778 /// Will panic if `up` is not normalized when `glam_assert` is enabled.
779 #[inline]
780 #[must_use]
look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self781 pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
782 Self::look_to_lh(eye, center.sub(eye).normalize(), up)
783 }
784
785 /// Creates a right-handed view matrix using a camera position, a focal point, and an up
786 /// direction.
787 ///
788 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
789 ///
790 /// # Panics
791 ///
792 /// Will panic if `up` is not normalized when `glam_assert` is enabled.
793 #[inline]
look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self794 pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
795 Self::look_to_rh(eye, center.sub(eye).normalize(), up)
796 }
797
798 /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
799 ///
800 /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
801 ///
802 /// This is the same as the OpenGL `gluPerspective` function.
803 /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
804 #[inline]
805 #[must_use]
perspective_rh_gl( fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32, ) -> Self806 pub fn perspective_rh_gl(
807 fov_y_radians: f32,
808 aspect_ratio: f32,
809 z_near: f32,
810 z_far: f32,
811 ) -> Self {
812 let inv_length = 1.0 / (z_near - z_far);
813 let f = 1.0 / math::tan(0.5 * fov_y_radians);
814 let a = f / aspect_ratio;
815 let b = (z_near + z_far) * inv_length;
816 let c = (2.0 * z_near * z_far) * inv_length;
817 Self::from_cols(
818 Vec4::new(a, 0.0, 0.0, 0.0),
819 Vec4::new(0.0, f, 0.0, 0.0),
820 Vec4::new(0.0, 0.0, b, -1.0),
821 Vec4::new(0.0, 0.0, c, 0.0),
822 )
823 }
824
825 /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
826 ///
827 /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
828 ///
829 /// # Panics
830 ///
831 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
832 /// enabled.
833 #[inline]
834 #[must_use]
perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self835 pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
836 glam_assert!(z_near > 0.0 && z_far > 0.0);
837 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
838 let h = cos_fov / sin_fov;
839 let w = h / aspect_ratio;
840 let r = z_far / (z_far - z_near);
841 Self::from_cols(
842 Vec4::new(w, 0.0, 0.0, 0.0),
843 Vec4::new(0.0, h, 0.0, 0.0),
844 Vec4::new(0.0, 0.0, r, 1.0),
845 Vec4::new(0.0, 0.0, -r * z_near, 0.0),
846 )
847 }
848
849 /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
850 ///
851 /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
852 ///
853 /// # Panics
854 ///
855 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
856 /// enabled.
857 #[inline]
858 #[must_use]
perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self859 pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
860 glam_assert!(z_near > 0.0 && z_far > 0.0);
861 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
862 let h = cos_fov / sin_fov;
863 let w = h / aspect_ratio;
864 let r = z_far / (z_near - z_far);
865 Self::from_cols(
866 Vec4::new(w, 0.0, 0.0, 0.0),
867 Vec4::new(0.0, h, 0.0, 0.0),
868 Vec4::new(0.0, 0.0, r, -1.0),
869 Vec4::new(0.0, 0.0, r * z_near, 0.0),
870 )
871 }
872
873 /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
874 ///
875 /// Like `perspective_lh`, but with an infinite value for `z_far`.
876 /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
877 ///
878 /// # Panics
879 ///
880 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
881 /// enabled.
882 #[inline]
883 #[must_use]
perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self884 pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
885 glam_assert!(z_near > 0.0);
886 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
887 let h = cos_fov / sin_fov;
888 let w = h / aspect_ratio;
889 Self::from_cols(
890 Vec4::new(w, 0.0, 0.0, 0.0),
891 Vec4::new(0.0, h, 0.0, 0.0),
892 Vec4::new(0.0, 0.0, 1.0, 1.0),
893 Vec4::new(0.0, 0.0, -z_near, 0.0),
894 )
895 }
896
897 /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
898 ///
899 /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
900 ///
901 /// # Panics
902 ///
903 /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
904 #[inline]
905 #[must_use]
perspective_infinite_reverse_lh( fov_y_radians: f32, aspect_ratio: f32, z_near: f32, ) -> Self906 pub fn perspective_infinite_reverse_lh(
907 fov_y_radians: f32,
908 aspect_ratio: f32,
909 z_near: f32,
910 ) -> Self {
911 glam_assert!(z_near > 0.0);
912 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
913 let h = cos_fov / sin_fov;
914 let w = h / aspect_ratio;
915 Self::from_cols(
916 Vec4::new(w, 0.0, 0.0, 0.0),
917 Vec4::new(0.0, h, 0.0, 0.0),
918 Vec4::new(0.0, 0.0, 0.0, 1.0),
919 Vec4::new(0.0, 0.0, z_near, 0.0),
920 )
921 }
922
923 /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
924 ///
925 /// Like `perspective_rh`, but with an infinite value for `z_far`.
926 /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
927 ///
928 /// # Panics
929 ///
930 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
931 /// enabled.
932 #[inline]
933 #[must_use]
perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self934 pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
935 glam_assert!(z_near > 0.0);
936 let f = 1.0 / math::tan(0.5 * fov_y_radians);
937 Self::from_cols(
938 Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
939 Vec4::new(0.0, f, 0.0, 0.0),
940 Vec4::new(0.0, 0.0, -1.0, -1.0),
941 Vec4::new(0.0, 0.0, -z_near, 0.0),
942 )
943 }
944
945 /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
946 ///
947 /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
948 ///
949 /// # Panics
950 ///
951 /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
952 #[inline]
953 #[must_use]
perspective_infinite_reverse_rh( fov_y_radians: f32, aspect_ratio: f32, z_near: f32, ) -> Self954 pub fn perspective_infinite_reverse_rh(
955 fov_y_radians: f32,
956 aspect_ratio: f32,
957 z_near: f32,
958 ) -> Self {
959 glam_assert!(z_near > 0.0);
960 let f = 1.0 / math::tan(0.5 * fov_y_radians);
961 Self::from_cols(
962 Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
963 Vec4::new(0.0, f, 0.0, 0.0),
964 Vec4::new(0.0, 0.0, 0.0, -1.0),
965 Vec4::new(0.0, 0.0, z_near, 0.0),
966 )
967 }
968
969 /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
970 /// range. This is the same as the OpenGL `glOrtho` function in OpenGL.
971 /// See
972 /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
973 ///
974 /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
975 #[inline]
976 #[must_use]
orthographic_rh_gl( left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32, ) -> Self977 pub fn orthographic_rh_gl(
978 left: f32,
979 right: f32,
980 bottom: f32,
981 top: f32,
982 near: f32,
983 far: f32,
984 ) -> Self {
985 let a = 2.0 / (right - left);
986 let b = 2.0 / (top - bottom);
987 let c = -2.0 / (far - near);
988 let tx = -(right + left) / (right - left);
989 let ty = -(top + bottom) / (top - bottom);
990 let tz = -(far + near) / (far - near);
991
992 Self::from_cols(
993 Vec4::new(a, 0.0, 0.0, 0.0),
994 Vec4::new(0.0, b, 0.0, 0.0),
995 Vec4::new(0.0, 0.0, c, 0.0),
996 Vec4::new(tx, ty, tz, 1.0),
997 )
998 }
999
1000 /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
1001 ///
1002 /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1003 #[inline]
1004 #[must_use]
orthographic_lh( left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32, ) -> Self1005 pub fn orthographic_lh(
1006 left: f32,
1007 right: f32,
1008 bottom: f32,
1009 top: f32,
1010 near: f32,
1011 far: f32,
1012 ) -> Self {
1013 let rcp_width = 1.0 / (right - left);
1014 let rcp_height = 1.0 / (top - bottom);
1015 let r = 1.0 / (far - near);
1016 Self::from_cols(
1017 Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1018 Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1019 Vec4::new(0.0, 0.0, r, 0.0),
1020 Vec4::new(
1021 -(left + right) * rcp_width,
1022 -(top + bottom) * rcp_height,
1023 -r * near,
1024 1.0,
1025 ),
1026 )
1027 }
1028
1029 /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
1030 ///
1031 /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1032 #[inline]
1033 #[must_use]
orthographic_rh( left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32, ) -> Self1034 pub fn orthographic_rh(
1035 left: f32,
1036 right: f32,
1037 bottom: f32,
1038 top: f32,
1039 near: f32,
1040 far: f32,
1041 ) -> Self {
1042 let rcp_width = 1.0 / (right - left);
1043 let rcp_height = 1.0 / (top - bottom);
1044 let r = 1.0 / (near - far);
1045 Self::from_cols(
1046 Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1047 Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1048 Vec4::new(0.0, 0.0, r, 0.0),
1049 Vec4::new(
1050 -(left + right) * rcp_width,
1051 -(top + bottom) * rcp_height,
1052 r * near,
1053 1.0,
1054 ),
1055 )
1056 }
1057
1058 /// Transforms the given 3D vector as a point, applying perspective correction.
1059 ///
1060 /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
1061 /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1062 ///
1063 /// This method assumes that `self` contains a projective transform.
1064 #[inline]
1065 #[must_use]
project_point3(&self, rhs: Vec3) -> Vec31066 pub fn project_point3(&self, rhs: Vec3) -> Vec3 {
1067 let mut res = self.x_axis.mul(rhs.x);
1068 res = self.y_axis.mul(rhs.y).add(res);
1069 res = self.z_axis.mul(rhs.z).add(res);
1070 res = self.w_axis.add(res);
1071 res = res.div(res.w);
1072 res.xyz()
1073 }
1074
1075 /// Transforms the given 3D vector as a point.
1076 ///
1077 /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1078 /// `1.0`.
1079 ///
1080 /// This method assumes that `self` contains a valid affine transform. It does not perform
1081 /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
1082 /// the [`Self::project_point3()`] method should be used instead.
1083 ///
1084 /// # Panics
1085 ///
1086 /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1087 #[inline]
1088 #[must_use]
transform_point3(&self, rhs: Vec3) -> Vec31089 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
1090 glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1091 let mut res = self.x_axis.mul(rhs.x);
1092 res = self.y_axis.mul(rhs.y).add(res);
1093 res = self.z_axis.mul(rhs.z).add(res);
1094 res = self.w_axis.add(res);
1095 res.xyz()
1096 }
1097
1098 /// Transforms the give 3D vector as a direction.
1099 ///
1100 /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1101 /// `0.0`.
1102 ///
1103 /// This method assumes that `self` contains a valid affine transform.
1104 ///
1105 /// # Panics
1106 ///
1107 /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1108 #[inline]
1109 #[must_use]
transform_vector3(&self, rhs: Vec3) -> Vec31110 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
1111 glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1112 let mut res = self.x_axis.mul(rhs.x);
1113 res = self.y_axis.mul(rhs.y).add(res);
1114 res = self.z_axis.mul(rhs.z).add(res);
1115 res.xyz()
1116 }
1117
1118 /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
1119 ///
1120 /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
1121 /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1122 ///
1123 /// This method assumes that `self` contains a projective transform.
1124 #[inline]
1125 #[must_use]
project_point3a(&self, rhs: Vec3A) -> Vec3A1126 pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
1127 self.project_point3(rhs.into()).into()
1128 }
1129
1130 /// Transforms the given [`Vec3A`] as 3D point.
1131 ///
1132 /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
1133 #[inline]
1134 #[must_use]
transform_point3a(&self, rhs: Vec3A) -> Vec3A1135 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
1136 self.transform_point3(rhs.into()).into()
1137 }
1138
1139 /// Transforms the give [`Vec3A`] as 3D vector.
1140 ///
1141 /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `0.0`.
1142 #[inline]
1143 #[must_use]
transform_vector3a(&self, rhs: Vec3A) -> Vec3A1144 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
1145 self.transform_vector3(rhs.into()).into()
1146 }
1147
1148 /// Transforms a 4D vector.
1149 #[inline]
1150 #[must_use]
mul_vec4(&self, rhs: Vec4) -> Vec41151 pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 {
1152 let mut res = self.x_axis.mul(rhs.x);
1153 res = res.add(self.y_axis.mul(rhs.y));
1154 res = res.add(self.z_axis.mul(rhs.z));
1155 res = res.add(self.w_axis.mul(rhs.w));
1156 res
1157 }
1158
1159 /// Multiplies two 4x4 matrices.
1160 #[inline]
1161 #[must_use]
mul_mat4(&self, rhs: &Self) -> Self1162 pub fn mul_mat4(&self, rhs: &Self) -> Self {
1163 Self::from_cols(
1164 self.mul(rhs.x_axis),
1165 self.mul(rhs.y_axis),
1166 self.mul(rhs.z_axis),
1167 self.mul(rhs.w_axis),
1168 )
1169 }
1170
1171 /// Adds two 4x4 matrices.
1172 #[inline]
1173 #[must_use]
add_mat4(&self, rhs: &Self) -> Self1174 pub fn add_mat4(&self, rhs: &Self) -> Self {
1175 Self::from_cols(
1176 self.x_axis.add(rhs.x_axis),
1177 self.y_axis.add(rhs.y_axis),
1178 self.z_axis.add(rhs.z_axis),
1179 self.w_axis.add(rhs.w_axis),
1180 )
1181 }
1182
1183 /// Subtracts two 4x4 matrices.
1184 #[inline]
1185 #[must_use]
sub_mat4(&self, rhs: &Self) -> Self1186 pub fn sub_mat4(&self, rhs: &Self) -> Self {
1187 Self::from_cols(
1188 self.x_axis.sub(rhs.x_axis),
1189 self.y_axis.sub(rhs.y_axis),
1190 self.z_axis.sub(rhs.z_axis),
1191 self.w_axis.sub(rhs.w_axis),
1192 )
1193 }
1194
1195 /// Multiplies a 4x4 matrix by a scalar.
1196 #[inline]
1197 #[must_use]
mul_scalar(&self, rhs: f32) -> Self1198 pub fn mul_scalar(&self, rhs: f32) -> Self {
1199 Self::from_cols(
1200 self.x_axis.mul(rhs),
1201 self.y_axis.mul(rhs),
1202 self.z_axis.mul(rhs),
1203 self.w_axis.mul(rhs),
1204 )
1205 }
1206
1207 /// Divides a 4x4 matrix by a scalar.
1208 #[inline]
1209 #[must_use]
div_scalar(&self, rhs: f32) -> Self1210 pub fn div_scalar(&self, rhs: f32) -> Self {
1211 let rhs = Vec4::splat(rhs);
1212 Self::from_cols(
1213 self.x_axis.div(rhs),
1214 self.y_axis.div(rhs),
1215 self.z_axis.div(rhs),
1216 self.w_axis.div(rhs),
1217 )
1218 }
1219
1220 /// Returns true if the absolute difference of all elements between `self` and `rhs`
1221 /// is less than or equal to `max_abs_diff`.
1222 ///
1223 /// This can be used to compare if two matrices contain similar elements. It works best
1224 /// when comparing with a known value. The `max_abs_diff` that should be used used
1225 /// depends on the values being compared against.
1226 ///
1227 /// For more see
1228 /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
1229 #[inline]
1230 #[must_use]
abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool1231 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
1232 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1233 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1234 && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1235 && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1236 }
1237
1238 /// Takes the absolute value of each element in `self`
1239 #[inline]
1240 #[must_use]
abs(&self) -> Self1241 pub fn abs(&self) -> Self {
1242 Self::from_cols(
1243 self.x_axis.abs(),
1244 self.y_axis.abs(),
1245 self.z_axis.abs(),
1246 self.w_axis.abs(),
1247 )
1248 }
1249
1250 #[inline]
as_dmat4(&self) -> DMat41251 pub fn as_dmat4(&self) -> DMat4 {
1252 DMat4::from_cols(
1253 self.x_axis.as_dvec4(),
1254 self.y_axis.as_dvec4(),
1255 self.z_axis.as_dvec4(),
1256 self.w_axis.as_dvec4(),
1257 )
1258 }
1259 }
1260
1261 impl Default for Mat4 {
1262 #[inline]
default() -> Self1263 fn default() -> Self {
1264 Self::IDENTITY
1265 }
1266 }
1267
1268 impl Add<Mat4> for Mat4 {
1269 type Output = Self;
1270 #[inline]
add(self, rhs: Self) -> Self::Output1271 fn add(self, rhs: Self) -> Self::Output {
1272 self.add_mat4(&rhs)
1273 }
1274 }
1275
1276 impl AddAssign<Mat4> for Mat4 {
1277 #[inline]
add_assign(&mut self, rhs: Self)1278 fn add_assign(&mut self, rhs: Self) {
1279 *self = self.add_mat4(&rhs);
1280 }
1281 }
1282
1283 impl Sub<Mat4> for Mat4 {
1284 type Output = Self;
1285 #[inline]
sub(self, rhs: Self) -> Self::Output1286 fn sub(self, rhs: Self) -> Self::Output {
1287 self.sub_mat4(&rhs)
1288 }
1289 }
1290
1291 impl SubAssign<Mat4> for Mat4 {
1292 #[inline]
sub_assign(&mut self, rhs: Self)1293 fn sub_assign(&mut self, rhs: Self) {
1294 *self = self.sub_mat4(&rhs);
1295 }
1296 }
1297
1298 impl Neg for Mat4 {
1299 type Output = Self;
1300 #[inline]
neg(self) -> Self::Output1301 fn neg(self) -> Self::Output {
1302 Self::from_cols(
1303 self.x_axis.neg(),
1304 self.y_axis.neg(),
1305 self.z_axis.neg(),
1306 self.w_axis.neg(),
1307 )
1308 }
1309 }
1310
1311 impl Mul<Mat4> for Mat4 {
1312 type Output = Self;
1313 #[inline]
mul(self, rhs: Self) -> Self::Output1314 fn mul(self, rhs: Self) -> Self::Output {
1315 self.mul_mat4(&rhs)
1316 }
1317 }
1318
1319 impl MulAssign<Mat4> for Mat4 {
1320 #[inline]
mul_assign(&mut self, rhs: Self)1321 fn mul_assign(&mut self, rhs: Self) {
1322 *self = self.mul_mat4(&rhs);
1323 }
1324 }
1325
1326 impl Mul<Vec4> for Mat4 {
1327 type Output = Vec4;
1328 #[inline]
mul(self, rhs: Vec4) -> Self::Output1329 fn mul(self, rhs: Vec4) -> Self::Output {
1330 self.mul_vec4(rhs)
1331 }
1332 }
1333
1334 impl Mul<Mat4> for f32 {
1335 type Output = Mat4;
1336 #[inline]
mul(self, rhs: Mat4) -> Self::Output1337 fn mul(self, rhs: Mat4) -> Self::Output {
1338 rhs.mul_scalar(self)
1339 }
1340 }
1341
1342 impl Mul<f32> for Mat4 {
1343 type Output = Self;
1344 #[inline]
mul(self, rhs: f32) -> Self::Output1345 fn mul(self, rhs: f32) -> Self::Output {
1346 self.mul_scalar(rhs)
1347 }
1348 }
1349
1350 impl MulAssign<f32> for Mat4 {
1351 #[inline]
mul_assign(&mut self, rhs: f32)1352 fn mul_assign(&mut self, rhs: f32) {
1353 *self = self.mul_scalar(rhs);
1354 }
1355 }
1356
1357 impl Div<Mat4> for f32 {
1358 type Output = Mat4;
1359 #[inline]
div(self, rhs: Mat4) -> Self::Output1360 fn div(self, rhs: Mat4) -> Self::Output {
1361 rhs.div_scalar(self)
1362 }
1363 }
1364
1365 impl Div<f32> for Mat4 {
1366 type Output = Self;
1367 #[inline]
div(self, rhs: f32) -> Self::Output1368 fn div(self, rhs: f32) -> Self::Output {
1369 self.div_scalar(rhs)
1370 }
1371 }
1372
1373 impl DivAssign<f32> for Mat4 {
1374 #[inline]
div_assign(&mut self, rhs: f32)1375 fn div_assign(&mut self, rhs: f32) {
1376 *self = self.div_scalar(rhs);
1377 }
1378 }
1379
1380 impl Sum<Self> for Mat4 {
sum<I>(iter: I) -> Self where I: Iterator<Item = Self>,1381 fn sum<I>(iter: I) -> Self
1382 where
1383 I: Iterator<Item = Self>,
1384 {
1385 iter.fold(Self::ZERO, Self::add)
1386 }
1387 }
1388
1389 impl<'a> Sum<&'a Self> for Mat4 {
sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Self>,1390 fn sum<I>(iter: I) -> Self
1391 where
1392 I: Iterator<Item = &'a Self>,
1393 {
1394 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1395 }
1396 }
1397
1398 impl Product for Mat4 {
product<I>(iter: I) -> Self where I: Iterator<Item = Self>,1399 fn product<I>(iter: I) -> Self
1400 where
1401 I: Iterator<Item = Self>,
1402 {
1403 iter.fold(Self::IDENTITY, Self::mul)
1404 }
1405 }
1406
1407 impl<'a> Product<&'a Self> for Mat4 {
product<I>(iter: I) -> Self where I: Iterator<Item = &'a Self>,1408 fn product<I>(iter: I) -> Self
1409 where
1410 I: Iterator<Item = &'a Self>,
1411 {
1412 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1413 }
1414 }
1415
1416 impl PartialEq for Mat4 {
1417 #[inline]
eq(&self, rhs: &Self) -> bool1418 fn eq(&self, rhs: &Self) -> bool {
1419 self.x_axis.eq(&rhs.x_axis)
1420 && self.y_axis.eq(&rhs.y_axis)
1421 && self.z_axis.eq(&rhs.z_axis)
1422 && self.w_axis.eq(&rhs.w_axis)
1423 }
1424 }
1425
1426 #[cfg(not(target_arch = "spirv"))]
1427 impl AsRef<[f32; 16]> for Mat4 {
1428 #[inline]
as_ref(&self) -> &[f32; 16]1429 fn as_ref(&self) -> &[f32; 16] {
1430 unsafe { &*(self as *const Self as *const [f32; 16]) }
1431 }
1432 }
1433
1434 #[cfg(not(target_arch = "spirv"))]
1435 impl AsMut<[f32; 16]> for Mat4 {
1436 #[inline]
as_mut(&mut self) -> &mut [f32; 16]1437 fn as_mut(&mut self) -> &mut [f32; 16] {
1438 unsafe { &mut *(self as *mut Self as *mut [f32; 16]) }
1439 }
1440 }
1441
1442 impl fmt::Debug for Mat4 {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1443 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1444 fmt.debug_struct(stringify!(Mat4))
1445 .field("x_axis", &self.x_axis)
1446 .field("y_axis", &self.y_axis)
1447 .field("z_axis", &self.z_axis)
1448 .field("w_axis", &self.w_axis)
1449 .finish()
1450 }
1451 }
1452
1453 impl fmt::Display for Mat4 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1455 if let Some(p) = f.precision() {
1456 write!(
1457 f,
1458 "[{:.*}, {:.*}, {:.*}, {:.*}]",
1459 p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
1460 )
1461 } else {
1462 write!(
1463 f,
1464 "[{}, {}, {}, {}]",
1465 self.x_axis, self.y_axis, self.z_axis, self.w_axis
1466 )
1467 }
1468 }
1469 }
1470