diff --git a/codegen/templates/mat.rs.tera b/codegen/templates/mat.rs.tera index 1ad3658a..47ab23e3 100644 --- a/codegen/templates/mat.rs.tera +++ b/codegen/templates/mat.rs.tera @@ -1989,7 +1989,7 @@ impl {{ self_t }} { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } @@ -2039,6 +2039,27 @@ impl {{ self_t }} { {% endif %} {% if self_t == "Mat4" %} + /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction. + /// + /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + #[must_use] + pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A { + {% if is_scalar %} + self.project_point3(rhs.into()).into() + {% else %} + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res = res.div(res.wwww()); + Vec3A::from_vec4(res) + {% endif %} + } + /// Transforms the given [`Vec3A`] as 3D point. /// /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. diff --git a/src/f32/coresimd/mat4.rs b/src/f32/coresimd/mat4.rs index f39c7d81..60829924 100644 --- a/src/f32/coresimd/mat4.rs +++ b/src/f32/coresimd/mat4.rs @@ -1121,7 +1121,7 @@ impl Mat4 { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } @@ -1168,6 +1168,23 @@ impl Mat4 { res.xyz() } + /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction. + /// + /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + #[must_use] + pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res = res.div(res.wwww()); + Vec3A::from_vec4(res) + } + /// Transforms the given [`Vec3A`] as 3D point. /// /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. diff --git a/src/f32/neon/mat4.rs b/src/f32/neon/mat4.rs index d8a16ecb..670e1982 100644 --- a/src/f32/neon/mat4.rs +++ b/src/f32/neon/mat4.rs @@ -1126,7 +1126,7 @@ impl Mat4 { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } @@ -1173,6 +1173,23 @@ impl Mat4 { res.xyz() } + /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction. + /// + /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + #[must_use] + pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res = res.div(res.wwww()); + Vec3A::from_vec4(res) + } + /// Transforms the given [`Vec3A`] as 3D point. /// /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. diff --git a/src/f32/scalar/mat4.rs b/src/f32/scalar/mat4.rs index 490de463..5541f262 100644 --- a/src/f32/scalar/mat4.rs +++ b/src/f32/scalar/mat4.rs @@ -1043,7 +1043,7 @@ impl Mat4 { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } @@ -1090,6 +1090,18 @@ impl Mat4 { res.xyz() } + /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction. + /// + /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + #[must_use] + pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A { + self.project_point3(rhs.into()).into() + } + /// Transforms the given [`Vec3A`] as 3D point. /// /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. diff --git a/src/f32/sse2/mat4.rs b/src/f32/sse2/mat4.rs index 88db90f6..062642c2 100644 --- a/src/f32/sse2/mat4.rs +++ b/src/f32/sse2/mat4.rs @@ -1130,7 +1130,7 @@ impl Mat4 { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } @@ -1177,6 +1177,23 @@ impl Mat4 { res.xyz() } + /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction. + /// + /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + #[must_use] + pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res = res.div(res.wwww()); + Vec3A::from_vec4(res) + } + /// Transforms the given [`Vec3A`] as 3D point. /// /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. diff --git a/src/f32/wasm32/mat4.rs b/src/f32/wasm32/mat4.rs index 43df8165..46f970bd 100644 --- a/src/f32/wasm32/mat4.rs +++ b/src/f32/wasm32/mat4.rs @@ -1121,7 +1121,7 @@ impl Mat4 { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } @@ -1168,6 +1168,23 @@ impl Mat4 { res.xyz() } + /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction. + /// + /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + #[must_use] + pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res = res.div(res.wwww()); + Vec3A::from_vec4(res) + } + /// Transforms the given [`Vec3A`] as 3D point. /// /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`. diff --git a/src/f64/dmat4.rs b/src/f64/dmat4.rs index 119b316e..763b8267 100644 --- a/src/f64/dmat4.rs +++ b/src/f64/dmat4.rs @@ -1025,7 +1025,7 @@ impl DMat4 { res = self.y_axis.mul(rhs.y).add(res); res = self.z_axis.mul(rhs.z).add(res); res = self.w_axis.add(res); - res = res.mul(res.wwww().recip()); + res = res.div(res.w); res.xyz() } diff --git a/tests/mat4.rs b/tests/mat4.rs index d9036331..e2a760c6 100644 --- a/tests/mat4.rs +++ b/tests/mat4.rs @@ -733,6 +733,35 @@ mod mat4 { ); }); + glam_test!(test_transform_vec3a, { + use glam::Vec3A; + let m = Mat4::from_axis_angle(Vec3::Z, deg(90.0)); + let result3 = m.transform_vector3a(Vec3A::Y); + assert_approx_eq!(Vec3A::new(-1.0, 0.0, 0.0), result3); + + let m = Mat4::from_scale_rotation_translation( + Vec3::new(0.5, 1.5, 2.0), + Quat::from_rotation_x(deg(90.0)), + Vec3::new(1.0, 2.0, 3.0), + ); + let result3 = m.transform_vector3a(Vec3A::Y); + assert_approx_eq!(Vec3A::new(0.0, 0.0, 1.5), result3, 1.0e-6); + + let result3 = m.transform_point3a(Vec3A::Y); + assert_approx_eq!(Vec3A::new(1.0, 2.0, 4.5), result3, 1.0e-6); + + let m = Mat4::from_cols( + vec4(8.0, 0.0, 0.0, 0.0), + vec4(0.0, 4.0, 0.0, 0.0), + vec4(0.0, 0.0, 2.0, 2.0), + vec4(0.0, 0.0, 0.0, 0.0), + ); + assert_approx_eq!( + Vec3A::new(4.0, 2.0, 1.0), + m.project_point3a(Vec3A::new(2.0, 2.0, 2.0)) + ); + }); + glam_test!(test_as, { use glam::DMat4; assert_eq!(