Merge 52d50d2e08
into 877d278785
This commit is contained in:
commit
030d34fd00
@ -55,7 +55,7 @@ pub use direction::*;
|
|||||||
pub use float_ord::*;
|
pub use float_ord::*;
|
||||||
pub use isometry::{Isometry2d, Isometry3d};
|
pub use isometry::{Isometry2d, Isometry3d};
|
||||||
pub use ops::FloatPow;
|
pub use ops::FloatPow;
|
||||||
pub use ray::{Ray2d, Ray3d};
|
pub use ray::{PlaneIntersectionMode, Ray2d, Ray3d};
|
||||||
pub use rects::*;
|
pub use rects::*;
|
||||||
pub use rotation2d::Rot2;
|
pub use rotation2d::Rot2;
|
||||||
|
|
||||||
@ -78,8 +78,8 @@ pub mod prelude {
|
|||||||
primitives::*,
|
primitives::*,
|
||||||
quat, uvec2, uvec3, uvec4, vec2, vec3, vec3a, vec4, BVec2, BVec3, BVec3A, BVec4, BVec4A,
|
quat, uvec2, uvec3, uvec4, vec2, vec3, vec3a, vec4, BVec2, BVec3, BVec3A, BVec4, BVec4A,
|
||||||
EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Isometry2d, Isometry3d, Mat2, Mat3, Mat3A,
|
EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Isometry2d, Isometry3d, Mat2, Mat3, Mat3A,
|
||||||
Mat4, Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2,
|
Mat4, PlaneIntersectionMode, Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect,
|
||||||
Vec2Swizzles, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles,
|
UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -55,6 +55,29 @@ impl Ray2d {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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(
|
||||||
|
feature = "bevy_reflect",
|
||||||
|
derive(Reflect),
|
||||||
|
reflect(Debug, PartialEq, Clone)
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
all(feature = "serialize", feature = "bevy_reflect"),
|
||||||
|
reflect(Deserialize, Serialize)
|
||||||
|
)]
|
||||||
|
pub enum PlaneIntersectionMode {
|
||||||
|
/// 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
|
||||||
|
/// (the side opposite to the normal).
|
||||||
|
BackFaceOnly,
|
||||||
|
/// Intersects both faces of the plane.
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
/// An infinite half-line starting at `origin` and going in `direction` in 3D space.
|
/// An infinite half-line starting at `origin` and going in `direction` in 3D space.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
@ -88,12 +111,24 @@ impl Ray3d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the distance to a plane if the ray intersects it
|
/// Get the distance to a plane if the ray intersects it
|
||||||
|
/// `plane_hit_mode` specifies which faces of the plane a ray can intersect
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn intersect_plane(&self, plane_origin: Vec3, plane: InfinitePlane3d) -> Option<f32> {
|
pub fn intersect_plane(
|
||||||
|
&self,
|
||||||
|
plane_origin: Vec3,
|
||||||
|
plane: InfinitePlane3d,
|
||||||
|
plane_hit_mode: PlaneIntersectionMode,
|
||||||
|
) -> Option<f32> {
|
||||||
let denominator = plane.normal.dot(*self.direction);
|
let denominator = plane.normal.dot(*self.direction);
|
||||||
if ops::abs(denominator) > f32::EPSILON {
|
if ops::abs(denominator) > f32::EPSILON {
|
||||||
let distance = (plane_origin - self.origin).dot(*plane.normal) / denominator;
|
let distance = (plane_origin - self.origin).dot(*plane.normal) / denominator;
|
||||||
if distance > f32::EPSILON {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,44 +181,145 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn intersect_plane_3d() {
|
fn intersect_plane_3d_both() {
|
||||||
let ray = Ray3d::new(Vec3::ZERO, Dir3::Z);
|
let ray = Ray3d::new(Vec3::ZERO, Dir3::Z);
|
||||||
|
|
||||||
// Orthogonal, and test that an inverse plane_normal has the same result
|
// Orthogonal, and test that an inverse plane_normal has the same result
|
||||||
assert_eq!(
|
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)
|
Some(1.0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
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)
|
Some(1.0)
|
||||||
);
|
);
|
||||||
assert!(ray
|
assert!(ray
|
||||||
.intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::Z))
|
.intersect_plane(
|
||||||
|
Vec3::NEG_Z,
|
||||||
|
InfinitePlane3d::new(Vec3::Z),
|
||||||
|
PlaneIntersectionMode::Both
|
||||||
|
)
|
||||||
.is_none());
|
.is_none());
|
||||||
assert!(ray
|
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());
|
.is_none());
|
||||||
|
|
||||||
// Diagonal
|
// Diagonal
|
||||||
assert_eq!(
|
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)
|
Some(1.0)
|
||||||
);
|
);
|
||||||
assert!(ray
|
assert!(ray
|
||||||
.intersect_plane(Vec3::NEG_Z, InfinitePlane3d::new(Vec3::ONE))
|
.intersect_plane(
|
||||||
|
Vec3::NEG_Z,
|
||||||
|
InfinitePlane3d::new(Vec3::ONE),
|
||||||
|
PlaneIntersectionMode::Both
|
||||||
|
)
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
// Parallel
|
// Parallel
|
||||||
assert!(ray
|
assert!(ray
|
||||||
.intersect_plane(Vec3::X, InfinitePlane3d::new(Vec3::X))
|
.intersect_plane(
|
||||||
|
Vec3::X,
|
||||||
|
InfinitePlane3d::new(Vec3::X),
|
||||||
|
PlaneIntersectionMode::Both
|
||||||
|
)
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
// Parallel with simulated rounding error
|
// Parallel with simulated rounding error
|
||||||
assert!(ray
|
assert!(ray
|
||||||
.intersect_plane(
|
.intersect_plane(
|
||||||
Vec3::X,
|
Vec3::X,
|
||||||
InfinitePlane3d::new(Vec3::X + Vec3::Z * f32::EPSILON)
|
InfinitePlane3d::new(Vec3::X + Vec3::Z * f32::EPSILON),
|
||||||
|
PlaneIntersectionMode::Both
|
||||||
|
)
|
||||||
|
.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!(ray
|
||||||
|
.intersect_plane(
|
||||||
|
Vec3::Z,
|
||||||
|
InfinitePlane3d::new(Vec3::Z),
|
||||||
|
PlaneIntersectionMode::FrontFaceOnly
|
||||||
|
)
|
||||||
|
.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
ray.intersect_plane(
|
||||||
|
Vec3::Z,
|
||||||
|
InfinitePlane3d::new(Vec3::NEG_Z),
|
||||||
|
PlaneIntersectionMode::FrontFaceOnly
|
||||||
|
),
|
||||||
|
Some(1.0)
|
||||||
|
);
|
||||||
|
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::NEG_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_eq!(
|
||||||
|
ray.intersect_plane(
|
||||||
|
Vec3::Z,
|
||||||
|
InfinitePlane3d::new(Vec3::Z),
|
||||||
|
PlaneIntersectionMode::BackFaceOnly
|
||||||
|
),
|
||||||
|
Some(1.0)
|
||||||
|
);
|
||||||
|
assert!(ray
|
||||||
|
.intersect_plane(
|
||||||
|
Vec3::Z,
|
||||||
|
InfinitePlane3d::new(Vec3::NEG_Z),
|
||||||
|
PlaneIntersectionMode::BackFaceOnly
|
||||||
|
)
|
||||||
|
.is_none());
|
||||||
|
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::NEG_Z),
|
||||||
|
PlaneIntersectionMode::BackFaceOnly
|
||||||
)
|
)
|
||||||
.is_none());
|
.is_none());
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ fn draw_cursor(
|
|||||||
&& let Ok(ray) = camera.viewport_to_world(camera_transform, cursor_position)
|
&& let Ok(ray) = camera.viewport_to_world(camera_transform, cursor_position)
|
||||||
// Calculate if and at what distance the ray is hitting the ground plane.
|
// Calculate if and at what distance the ray is hitting the ground plane.
|
||||||
&& let Some(distance) =
|
&& 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);
|
let point = ray.get_point(distance);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
color::palettes::css::*,
|
color::palettes::css::*,
|
||||||
core_pipeline::Skybox,
|
core_pipeline::Skybox,
|
||||||
math::{uvec3, vec3},
|
math::{uvec3, vec3, PlaneIntersectionMode},
|
||||||
pbr::{
|
pbr::{
|
||||||
irradiance_volume::IrradianceVolume, ExtendedMaterial, MaterialExtension, NotShadowCaster,
|
irradiance_volume::IrradianceVolume, ExtendedMaterial, MaterialExtension, NotShadowCaster,
|
||||||
},
|
},
|
||||||
@ -466,7 +466,11 @@ fn handle_mouse_clicks(
|
|||||||
let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
|
let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
|
||||||
return;
|
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;
|
return;
|
||||||
};
|
};
|
||||||
let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance;
|
let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance;
|
||||||
|
Loading…
Reference in New Issue
Block a user