From a6d68d6698653acf9f4621316ab90ed934511dc0 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 02:43:51 +0200 Subject: [PATCH 1/9] feat: add PlaneIntersectionMode Allows to choose which face side of the plane the Ray3d intersects. --- crates/bevy_math/src/lib.rs | 4 +-- crates/bevy_math/src/ray.rs | 48 ++++++++++++++++++++++------- examples/3d/3d_viewport_to_world.rs | 2 +- examples/3d/irradiance_volumes.rs | 4 +-- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 070483e777..0955c6e04d 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -55,7 +55,7 @@ pub use direction::*; pub use float_ord::*; pub use isometry::{Isometry2d, Isometry3d}; pub use ops::FloatPow; -pub use ray::{Ray2d, Ray3d}; +pub use ray::{Ray2d, Ray3d, PlaneIntersectionMode}; pub use rects::*; pub use rotation2d::Rot2; @@ -78,7 +78,7 @@ pub mod prelude { primitives::*, quat, uvec2, uvec3, uvec4, vec2, vec3, vec3a, vec4, BVec2, BVec3, BVec3A, BVec4, BVec4A, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Isometry2d, Isometry3d, Mat2, Mat3, Mat3A, - Mat4, Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, + Mat4, Quat, Ray2d, Ray3d, PlaneIntersectionMode, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, }; diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index 5fe9c3740a..66e3fb8822 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -55,6 +55,24 @@ impl Ray2d { } } +/// Defines if the Ray3d should intersect the plane only on the front face, back face, or both. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "bevy_reflect", + derive(Reflect), + reflect(Debug, PartialEq, Clone) +)] +#[cfg_attr( + all(feature = "serialize", feature = "bevy_reflect"), + reflect(Deserialize, Serialize) +)] +pub enum PlaneIntersectionMode { + FrontFaceOnly, + BackFaceOnly, + Both, +} + /// An infinite half-line starting at `origin` and going in `direction` in 3D space. #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] @@ -88,13 +106,20 @@ impl Ray3d { } /// Get the distance to a plane if the ray intersects it + /// `plane_hit_mode` specifies which face of the plane the ray should hit #[inline] - pub fn intersect_plane(&self, plane_origin: Vec3, plane: InfinitePlane3d) -> Option { + pub fn intersect_plane(&self, plane_origin: Vec3, plane: InfinitePlane3d, plane_hit_mode: PlaneIntersectionMode) -> Option { let denominator = plane.normal.dot(*self.direction); if ops::abs(denominator) > f32::EPSILON { let distance = (plane_origin - self.origin).dot(*plane.normal) / denominator; if distance > f32::EPSILON { - return Some(distance); + if match plane_hit_mode { + PlaneIntersectionMode::Both => true, + PlaneIntersectionMode::FrontFaceOnly => denominator < 0.0, + PlaneIntersectionMode::BackFaceOnly => denominator > 0.0, + } { + return Some(distance); + } } } None @@ -146,44 +171,45 @@ mod tests { } #[test] - fn intersect_plane_3d() { + fn intersect_plane_3d_both() { let ray = Ray3d::new(Vec3::ZERO, Dir3::Z); // Orthogonal, and test that an inverse plane_normal has the same result assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z)), + ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::Both), Some(1.0) ); assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z)), + ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::Both), Some(1.0) ); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z)) + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::Both) .is_none()); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::NEG_Z)) + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::Both) .is_none()); // Diagonal assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::ONE)), + ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::ONE), PlaneIntersectionMode::Both), Some(1.0) ); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::ONE)) + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::ONE), PlaneIntersectionMode::Both) .is_none()); // Parallel assert!(ray - .intersect_plane(Vec3::X, InfinitePlane3d::new(Vec3::X)) + .intersect_plane(Vec3::X, InfinitePlane3d::new(Vec3::X), PlaneIntersectionMode::Both) .is_none()); // Parallel with simulated rounding error assert!(ray .intersect_plane( Vec3::X, - InfinitePlane3d::new(Vec3::X + Vec3::Z * f32::EPSILON) + InfinitePlane3d::new(Vec3::X + Vec3::Z * f32::EPSILON), + PlaneIntersectionMode::Both ) .is_none()); } diff --git a/examples/3d/3d_viewport_to_world.rs b/examples/3d/3d_viewport_to_world.rs index 883121779a..dde3272197 100644 --- a/examples/3d/3d_viewport_to_world.rs +++ b/examples/3d/3d_viewport_to_world.rs @@ -23,7 +23,7 @@ fn draw_cursor( && let Ok(ray) = camera.viewport_to_world(camera_transform, cursor_position) // Calculate if and at what distance the ray is hitting the ground plane. && let Some(distance) = - ray.intersect_plane(ground.translation(), InfinitePlane3d::new(ground.up())) + ray.intersect_plane(ground.translation(), InfinitePlane3d::new(ground.up()), PlaneIntersectionMode::Both) { let point = ray.get_point(distance); diff --git a/examples/3d/irradiance_volumes.rs b/examples/3d/irradiance_volumes.rs index 80373512db..4f8f2b9c18 100644 --- a/examples/3d/irradiance_volumes.rs +++ b/examples/3d/irradiance_volumes.rs @@ -16,7 +16,7 @@ use bevy::{ color::palettes::css::*, core_pipeline::Skybox, - math::{uvec3, vec3}, + math::{uvec3, vec3, PlaneIntersectionMode}, pbr::{ irradiance_volume::IrradianceVolume, ExtendedMaterial, MaterialExtension, NotShadowCaster, }, @@ -466,7 +466,7 @@ fn handle_mouse_clicks( let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else { return; }; - let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y)) else { + let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y), PlaneIntersectionMode::Both) else { return; }; let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance; From b31df43b23b6028fa6a20a1c4f08f4541cd9176a Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 02:51:26 +0200 Subject: [PATCH 2/9] test: add tests for PlaneIntersectionMode --- crates/bevy_math/src/ray.rs | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index 66e3fb8822..af8f0a7e86 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -213,4 +213,44 @@ mod tests { ) .is_none()); } + + #[test] + fn intersect_plane_3d_only_front() { + let ray = Ray3d::new(Vec3::ZERO, Dir3::Z); + + // Orthogonal, and test that ray intersects only the front face + assert_eq!( + ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly), + Some(1.0) + ); + assert!(ray + .intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::FrontFaceOnly) + .is_none()); + assert!(ray + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly) + .is_none()); + assert!(ray + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly) + .is_none()); + } + + #[test] + fn intersect_plane_3d_only_back() { + let ray = Ray3d::new(Vec3::ZERO, Dir3::Z); + + // Orthogonal, and test that ray intersects only the back face + assert!(ray + .intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly) + .is_none()); + assert_eq!( + ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly), + Some(1.0) + ); + assert!(ray + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly) + .is_none()); + assert!(ray + .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly) + .is_none()); + } } From d26bd57ea7aaab587b49aa5392eb3f59864ce8f1 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 02:56:38 +0200 Subject: [PATCH 3/9] style: fix format --- crates/bevy_math/src/lib.rs | 6 +- crates/bevy_math/src/ray.rs | 97 ++++++++++++++++++++++++++----- examples/3d/irradiance_volumes.rs | 6 +- 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 0955c6e04d..c906dd4c92 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -55,7 +55,7 @@ pub use direction::*; pub use float_ord::*; pub use isometry::{Isometry2d, Isometry3d}; pub use ops::FloatPow; -pub use ray::{Ray2d, Ray3d, PlaneIntersectionMode}; +pub use ray::{PlaneIntersectionMode, Ray2d, Ray3d}; pub use rects::*; pub use rotation2d::Rot2; @@ -78,8 +78,8 @@ pub mod prelude { primitives::*, quat, uvec2, uvec3, uvec4, vec2, vec3, vec3a, vec4, BVec2, BVec3, BVec3A, BVec4, BVec4A, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Isometry2d, Isometry3d, Mat2, Mat3, Mat3A, - Mat4, Quat, Ray2d, Ray3d, PlaneIntersectionMode, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, - Vec2Swizzles, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, + Mat4, PlaneIntersectionMode, Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, + UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, }; #[doc(hidden)] diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index af8f0a7e86..1f260f63c9 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -108,7 +108,12 @@ impl Ray3d { /// Get the distance to a plane if the ray intersects it /// `plane_hit_mode` specifies which face of the plane the ray should hit #[inline] - pub fn intersect_plane(&self, plane_origin: Vec3, plane: InfinitePlane3d, plane_hit_mode: PlaneIntersectionMode) -> Option { + pub fn intersect_plane( + &self, + plane_origin: Vec3, + plane: InfinitePlane3d, + plane_hit_mode: PlaneIntersectionMode, + ) -> Option { let denominator = plane.normal.dot(*self.direction); if ops::abs(denominator) > f32::EPSILON { let distance = (plane_origin - self.origin).dot(*plane.normal) / denominator; @@ -176,32 +181,60 @@ mod tests { // Orthogonal, and test that an inverse plane_normal has the same result assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::Both), + ray.intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::Both + ), Some(1.0) ); assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::Both), + ray.intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::NEG_Z), + PlaneIntersectionMode::Both + ), Some(1.0) ); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::Both) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::Both + ) .is_none()); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::Both) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::NEG_Z), + PlaneIntersectionMode::Both + ) .is_none()); // Diagonal assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::ONE), PlaneIntersectionMode::Both), + ray.intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::ONE), + PlaneIntersectionMode::Both + ), Some(1.0) ); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::ONE), PlaneIntersectionMode::Both) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::ONE), + PlaneIntersectionMode::Both + ) .is_none()); // Parallel assert!(ray - .intersect_plane(Vec3::X, InfinitePlane3d::new(Vec3::X), PlaneIntersectionMode::Both) + .intersect_plane( + Vec3::X, + InfinitePlane3d::new(Vec3::X), + PlaneIntersectionMode::Both + ) .is_none()); // Parallel with simulated rounding error @@ -220,17 +253,33 @@ mod tests { // Orthogonal, and test that ray intersects only the front face assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly), + ray.intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::FrontFaceOnly + ), Some(1.0) ); assert!(ray - .intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::FrontFaceOnly) + .intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::NEG_Z), + PlaneIntersectionMode::FrontFaceOnly + ) .is_none()); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::FrontFaceOnly + ) .is_none()); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::FrontFaceOnly + ) .is_none()); } @@ -240,17 +289,33 @@ mod tests { // Orthogonal, and test that ray intersects only the back face assert!(ray - .intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly) + .intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::BackFaceOnly + ) .is_none()); assert_eq!( - ray.intersect_plane(Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly), + ray.intersect_plane( + Vec3::Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::BackFaceOnly + ), Some(1.0) ); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::BackFaceOnly + ) .is_none()); assert!(ray - .intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::BackFaceOnly) + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::Z), + PlaneIntersectionMode::BackFaceOnly + ) .is_none()); } } diff --git a/examples/3d/irradiance_volumes.rs b/examples/3d/irradiance_volumes.rs index 4f8f2b9c18..8ccc7fe2c4 100644 --- a/examples/3d/irradiance_volumes.rs +++ b/examples/3d/irradiance_volumes.rs @@ -466,7 +466,11 @@ fn handle_mouse_clicks( let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else { return; }; - let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y), PlaneIntersectionMode::Both) else { + let Some(ray_distance) = ray.intersect_plane( + Vec3::ZERO, + InfinitePlane3d::new(Vec3::Y), + PlaneIntersectionMode::Both, + ) else { return; }; let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance; From 12be5be3776b58245bebc17aaa13c06fd5b907a8 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 03:53:17 +0200 Subject: [PATCH 4/9] fix: tests for PlaneIntersectionMode --- crates/bevy_math/src/ray.rs | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index 1f260f63c9..eb3559b206 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -252,21 +252,20 @@ mod tests { let ray = Ray3d::new(Vec3::ZERO, Dir3::Z); // Orthogonal, and test that ray intersects only the front face - assert_eq!( + assert!( ray.intersect_plane( Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly - ), - Some(1.0) - ); - assert!(ray + ) + .is_none()); + assert_eq!(ray .intersect_plane( Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::FrontFaceOnly - ) - .is_none()); + ), + Some(1.0)); assert!(ray .intersect_plane( Vec3::NEG_Z, @@ -277,7 +276,7 @@ mod tests { assert!(ray .intersect_plane( Vec3::NEG_Z, - InfinitePlane3d::new(Vec3::Z), + InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::FrontFaceOnly ) .is_none()); @@ -288,13 +287,6 @@ mod tests { let ray = Ray3d::new(Vec3::ZERO, Dir3::Z); // Orthogonal, and test that ray intersects only the back face - assert!(ray - .intersect_plane( - Vec3::Z, - InfinitePlane3d::new(Vec3::Z), - PlaneIntersectionMode::BackFaceOnly - ) - .is_none()); assert_eq!( ray.intersect_plane( Vec3::Z, @@ -305,8 +297,8 @@ mod tests { ); assert!(ray .intersect_plane( - Vec3::NEG_Z, - InfinitePlane3d::new(Vec3::Z), + Vec3::Z, + InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::BackFaceOnly ) .is_none()); @@ -317,5 +309,12 @@ mod tests { PlaneIntersectionMode::BackFaceOnly ) .is_none()); + assert!(ray + .intersect_plane( + Vec3::NEG_Z, + InfinitePlane3d::new(Vec3::NEG_Z), + PlaneIntersectionMode::BackFaceOnly + ) + .is_none()); } } From d502a9e099bf44339c54379a6908e15dc00c5b54 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 16:49:29 +0200 Subject: [PATCH 5/9] style: fix format --- crates/bevy_math/src/ray.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index eb3559b206..6f9a30f703 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -252,20 +252,21 @@ mod tests { let ray = Ray3d::new(Vec3::ZERO, Dir3::Z); // Orthogonal, and test that ray intersects only the front face - assert!( - ray.intersect_plane( + assert!(ray + .intersect_plane( Vec3::Z, InfinitePlane3d::new(Vec3::Z), PlaneIntersectionMode::FrontFaceOnly ) .is_none()); - assert_eq!(ray - .intersect_plane( + assert_eq!( + ray.intersect_plane( Vec3::Z, InfinitePlane3d::new(Vec3::NEG_Z), PlaneIntersectionMode::FrontFaceOnly ), - Some(1.0)); + Some(1.0) + ); assert!(ray .intersect_plane( Vec3::NEG_Z, From ab532fde733e32e3cd40b7665418e8fe89a93503 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 16:50:32 +0200 Subject: [PATCH 6/9] docs: add documentation for PlaneIntersectionMode --- crates/bevy_math/src/ray.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index 6f9a30f703..3f6a64c759 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -68,8 +68,11 @@ impl Ray2d { reflect(Deserialize, Serialize) )] pub enum PlaneIntersectionMode { + /// Intersects only the front face of the plane. FrontFaceOnly, + /// Intersects only the back face of the plane. BackFaceOnly, + /// Intersects both faces of the plane. Both, } From b0ce95461836f47e16c82f1ddaf5d28ad434d369 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 20:27:57 +0200 Subject: [PATCH 7/9] style: fix style --- crates/bevy_math/src/ray.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index 3f6a64c759..49d6376e95 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -120,14 +120,14 @@ impl Ray3d { let denominator = plane.normal.dot(*self.direction); if ops::abs(denominator) > f32::EPSILON { let distance = (plane_origin - self.origin).dot(*plane.normal) / denominator; - if distance > f32::EPSILON { - if match plane_hit_mode { + if distance > f32::EPSILON + && match plane_hit_mode { PlaneIntersectionMode::Both => true, PlaneIntersectionMode::FrontFaceOnly => denominator < 0.0, PlaneIntersectionMode::BackFaceOnly => denominator > 0.0, - } { - return Some(distance); } + { + return Some(distance); } } None From 6cc651ed8f65c7797bca4e0489826b7f7fc8370a Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 20:47:29 +0200 Subject: [PATCH 8/9] docs: update documentation --- crates/bevy_math/src/ray.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index 49d6376e95..b3fd27b77b 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -55,7 +55,7 @@ impl Ray2d { } } -/// Defines if the Ray3d should intersect the plane only on the front face, back face, or both. +/// Controls which faces of the plane a ray can intersect. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -68,9 +68,11 @@ impl Ray2d { reflect(Deserialize, Serialize) )] pub enum PlaneIntersectionMode { - /// Intersects only the front face of the plane. + /// Intersects only the front face of the plane + /// (the side from which the plane normal points towards the ray). FrontFaceOnly, - /// Intersects only the back face of the plane. + /// Intersects only the back face of the plane + /// (the side opposite to the normal). BackFaceOnly, /// Intersects both faces of the plane. Both, From 52d50d2e08ed784091c7d7eb848a7c253def5861 Mon Sep 17 00:00:00 2001 From: Mateusz Stulczewski Date: Wed, 16 Jul 2025 21:25:15 +0200 Subject: [PATCH 9/9] docs: update documentation --- crates/bevy_math/src/ray.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index b3fd27b77b..0c1c87c853 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -111,7 +111,7 @@ impl Ray3d { } /// Get the distance to a plane if the ray intersects it - /// `plane_hit_mode` specifies which face of the plane the ray should hit + /// `plane_hit_mode` specifies which faces of the plane a ray can intersect #[inline] pub fn intersect_plane( &self,