Add volume cast intersection tests (#11586)
# Objective - Add a basic form of shapecasting for bounding volumes ## Solution - Implement AabbCast2d, AabbCast3d, BoundingCircleCast, and BoundingSphereCast - These are really just raycasts, but they modify the volumes the ray is casting against - The tests are slightly simpler, since they just use the raycast code for the heavy lifting
This commit is contained in:
		
							parent
							
								
									76d32c9d5a
								
							
						
					
					
						commit
						1b98de68fe
					
				| @ -29,7 +29,7 @@ pub trait Bounded2d { | ||||
| 
 | ||||
| /// A 2D axis-aligned bounding box, or bounding rectangle
 | ||||
| #[doc(alias = "BoundingRectangle")] | ||||
| #[derive(Clone, Debug)] | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| pub struct Aabb2d { | ||||
|     /// The minimum, conventionally bottom-left, point of the box
 | ||||
|     pub min: Vec2, | ||||
| @ -328,7 +328,7 @@ mod aabb2d_tests { | ||||
| use crate::primitives::Circle; | ||||
| 
 | ||||
| /// A bounding circle
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| pub struct BoundingCircle { | ||||
|     /// The center of the bounding circle
 | ||||
|     pub center: Vec2, | ||||
| @ -425,10 +425,10 @@ impl BoundingVolume for BoundingCircle { | ||||
|         let diff = other.center - self.center; | ||||
|         let length = diff.length(); | ||||
|         if self.radius() >= length + other.radius() { | ||||
|             return self.clone(); | ||||
|             return *self; | ||||
|         } | ||||
|         if other.radius() >= length + self.radius() { | ||||
|             return other.clone(); | ||||
|             return *other; | ||||
|         } | ||||
|         let dir = diff / length; | ||||
|         Self::new( | ||||
|  | ||||
| @ -24,7 +24,7 @@ pub trait Bounded3d { | ||||
| } | ||||
| 
 | ||||
| /// A 3D axis-aligned bounding box
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| pub struct Aabb3d { | ||||
|     /// The minimum point of the box
 | ||||
|     pub min: Vec3, | ||||
| @ -324,7 +324,7 @@ mod aabb3d_tests { | ||||
| use crate::primitives::Sphere; | ||||
| 
 | ||||
| /// A bounding sphere
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| pub struct BoundingSphere { | ||||
|     /// The center of the bounding sphere
 | ||||
|     pub center: Vec3, | ||||
| @ -417,10 +417,10 @@ impl BoundingVolume for BoundingSphere { | ||||
|         let diff = other.center - self.center; | ||||
|         let length = diff.length(); | ||||
|         if self.radius() >= length + other.radius() { | ||||
|             return self.clone(); | ||||
|             return *self; | ||||
|         } | ||||
|         if other.radius() >= length + self.radius() { | ||||
|             return other.clone(); | ||||
|             return *other; | ||||
|         } | ||||
|         let dir = diff / length; | ||||
|         Self::new( | ||||
|  | ||||
| @ -13,7 +13,7 @@ pub struct RayTest2d { | ||||
| } | ||||
| 
 | ||||
| impl RayTest2d { | ||||
|     /// Construct a [`RayTest2d`] from an origin, [`Direction2d`] and max distance.
 | ||||
|     /// Construct a [`RayTest2d`] from an origin, [`Direction2d`], and max distance.
 | ||||
|     pub fn new(origin: Vec2, direction: Direction2d, max: f32) -> Self { | ||||
|         Self::from_ray(Ray2d { origin, direction }, max) | ||||
|     } | ||||
| @ -98,6 +98,80 @@ impl IntersectsVolume<BoundingCircle> for RayTest2d { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// An intersection test that casts an [`Aabb2d`] along a ray.
 | ||||
| #[derive(Debug)] | ||||
| pub struct AabbCast2d { | ||||
|     /// The ray along which to cast the bounding volume
 | ||||
|     pub ray: RayTest2d, | ||||
|     /// The aabb that is being cast
 | ||||
|     pub aabb: Aabb2d, | ||||
| } | ||||
| 
 | ||||
| impl AabbCast2d { | ||||
|     /// Construct an [`AabbCast2d`] from an [`Aabb2d`], origin, [`Direction2d`], and max distance.
 | ||||
|     pub fn new(aabb: Aabb2d, origin: Vec2, direction: Direction2d, max: f32) -> Self { | ||||
|         Self::from_ray(aabb, Ray2d { origin, direction }, max) | ||||
|     } | ||||
| 
 | ||||
|     /// Construct an [`AabbCast2d`] from an [`Aabb2d`], [`Ray2d`], and max distance.
 | ||||
|     pub fn from_ray(aabb: Aabb2d, ray: Ray2d, max: f32) -> Self { | ||||
|         Self { | ||||
|             ray: RayTest2d::from_ray(ray, max), | ||||
|             aabb, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get the distance at which the [`Aabb2d`]s collide, if at all.
 | ||||
|     pub fn aabb_collision_at(&self, mut aabb: Aabb2d) -> Option<f32> { | ||||
|         aabb.min -= self.aabb.max; | ||||
|         aabb.max -= self.aabb.min; | ||||
|         self.ray.aabb_intersection_at(&aabb) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl IntersectsVolume<Aabb2d> for AabbCast2d { | ||||
|     fn intersects(&self, volume: &Aabb2d) -> bool { | ||||
|         self.aabb_collision_at(*volume).is_some() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// An intersection test that casts a [`BoundingCircle`] along a ray.
 | ||||
| #[derive(Debug)] | ||||
| pub struct BoundingCircleCast { | ||||
|     /// The ray along which to cast the bounding volume
 | ||||
|     pub ray: RayTest2d, | ||||
|     /// The circle that is being cast
 | ||||
|     pub circle: BoundingCircle, | ||||
| } | ||||
| 
 | ||||
| impl BoundingCircleCast { | ||||
|     /// Construct a [`BoundingCircleCast`] from a [`BoundingCircle`], origin, [`Direction2d`], and max distance.
 | ||||
|     pub fn new(circle: BoundingCircle, origin: Vec2, direction: Direction2d, max: f32) -> Self { | ||||
|         Self::from_ray(circle, Ray2d { origin, direction }, max) | ||||
|     } | ||||
| 
 | ||||
|     /// Construct a [`BoundingCircleCast`] from a [`BoundingCircle`], [`Ray2d`], and max distance.
 | ||||
|     pub fn from_ray(circle: BoundingCircle, ray: Ray2d, max: f32) -> Self { | ||||
|         Self { | ||||
|             ray: RayTest2d::from_ray(ray, max), | ||||
|             circle, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get the distance at which the [`BoundingCircle`]s collide, if at all.
 | ||||
|     pub fn circle_collision_at(&self, mut circle: BoundingCircle) -> Option<f32> { | ||||
|         circle.center -= self.circle.center; | ||||
|         circle.circle.radius += self.circle.radius(); | ||||
|         self.ray.circle_intersection_at(&circle) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl IntersectsVolume<BoundingCircle> for BoundingCircleCast { | ||||
|     fn intersects(&self, volume: &BoundingCircle) -> bool { | ||||
|         self.circle_collision_at(*volume).is_some() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| @ -327,4 +401,138 @@ mod tests { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_aabb_cast_hits() { | ||||
|         for (test, volume, expected_distance) in &[ | ||||
|             ( | ||||
|                 // Hit the center of the aabb, that a ray would've also hit
 | ||||
|                 AabbCast2d::new( | ||||
|                     Aabb2d::new(Vec2::ZERO, Vec2::ONE), | ||||
|                     Vec2::ZERO, | ||||
|                     Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb2d::new(Vec2::Y * 5., Vec2::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the center of the aabb, but from the other side
 | ||||
|                 AabbCast2d::new( | ||||
|                     Aabb2d::new(Vec2::ZERO, Vec2::ONE), | ||||
|                     Vec2::Y * 10., | ||||
|                     -Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb2d::new(Vec2::Y * 5., Vec2::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the edge of the aabb, that a ray would've missed
 | ||||
|                 AabbCast2d::new( | ||||
|                     Aabb2d::new(Vec2::ZERO, Vec2::ONE), | ||||
|                     Vec2::X * 1.5, | ||||
|                     Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb2d::new(Vec2::Y * 5., Vec2::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the edge of the aabb, by casting an off-center AABB
 | ||||
|                 AabbCast2d::new( | ||||
|                     Aabb2d::new(Vec2::X * -2., Vec2::ONE), | ||||
|                     Vec2::X * 3., | ||||
|                     Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb2d::new(Vec2::Y * 5., Vec2::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|         ] { | ||||
|             let case = format!( | ||||
|                 "Case:\n  Test: {:?}\n  Volume: {:?}\n  Expected distance: {:?}", | ||||
|                 test, volume, expected_distance | ||||
|             ); | ||||
|             assert!(test.intersects(volume), "{}", case); | ||||
|             let actual_distance = test.aabb_collision_at(*volume).unwrap(); | ||||
|             assert!( | ||||
|                 (actual_distance - expected_distance).abs() < EPSILON, | ||||
|                 "{}\n  Actual distance: {}", | ||||
|                 case, | ||||
|                 actual_distance | ||||
|             ); | ||||
| 
 | ||||
|             let inverted_ray = | ||||
|                 RayTest2d::new(test.ray.ray.origin, -test.ray.ray.direction, test.ray.max); | ||||
|             assert!(!inverted_ray.intersects(volume), "{}", case); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_circle_cast_hits() { | ||||
|         for (test, volume, expected_distance) in &[ | ||||
|             ( | ||||
|                 // Hit the center of the bounding circle, that a ray would've also hit
 | ||||
|                 BoundingCircleCast::new( | ||||
|                     BoundingCircle::new(Vec2::ZERO, 1.), | ||||
|                     Vec2::ZERO, | ||||
|                     Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingCircle::new(Vec2::Y * 5., 1.), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the center of the bounding circle, but from the other side
 | ||||
|                 BoundingCircleCast::new( | ||||
|                     BoundingCircle::new(Vec2::ZERO, 1.), | ||||
|                     Vec2::Y * 10., | ||||
|                     -Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingCircle::new(Vec2::Y * 5., 1.), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the bounding circle off-center, that a ray would've missed
 | ||||
|                 BoundingCircleCast::new( | ||||
|                     BoundingCircle::new(Vec2::ZERO, 1.), | ||||
|                     Vec2::X * 1.5, | ||||
|                     Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingCircle::new(Vec2::Y * 5., 1.), | ||||
|                 3.677, | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the bounding circle off-center, by casting a circle that is off-center
 | ||||
|                 BoundingCircleCast::new( | ||||
|                     BoundingCircle::new(Vec2::X * -1.5, 1.), | ||||
|                     Vec2::X * 3., | ||||
|                     Direction2d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingCircle::new(Vec2::Y * 5., 1.), | ||||
|                 3.677, | ||||
|             ), | ||||
|         ] { | ||||
|             let case = format!( | ||||
|                 "Case:\n  Test: {:?}\n  Volume: {:?}\n  Expected distance: {:?}", | ||||
|                 test, volume, expected_distance | ||||
|             ); | ||||
|             assert!(test.intersects(volume), "{}", case); | ||||
|             let actual_distance = test.circle_collision_at(*volume).unwrap(); | ||||
|             assert!( | ||||
|                 (actual_distance - expected_distance).abs() < EPSILON, | ||||
|                 "{}\n  Actual distance: {}", | ||||
|                 case, | ||||
|                 actual_distance | ||||
|             ); | ||||
| 
 | ||||
|             let inverted_ray = | ||||
|                 RayTest2d::new(test.ray.ray.origin, -test.ray.ray.direction, test.ray.max); | ||||
|             assert!(!inverted_ray.intersects(volume), "{}", case); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -13,7 +13,7 @@ pub struct RayTest3d { | ||||
| } | ||||
| 
 | ||||
| impl RayTest3d { | ||||
|     /// Construct a [`RayTest3d`] from an origin, [`Direction3d`] and max distance.
 | ||||
|     /// Construct a [`RayTest3d`] from an origin, [`Direction3d`], and max distance.
 | ||||
|     pub fn new(origin: Vec3, direction: Direction3d, max: f32) -> Self { | ||||
|         Self::from_ray(Ray3d { origin, direction }, max) | ||||
|     } | ||||
| @ -105,6 +105,80 @@ impl IntersectsVolume<BoundingSphere> for RayTest3d { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// An intersection test that casts an [`Aabb3d`] along a ray.
 | ||||
| #[derive(Debug)] | ||||
| pub struct AabbCast3d { | ||||
|     /// The ray along which to cast the bounding volume
 | ||||
|     pub ray: RayTest3d, | ||||
|     /// The aabb that is being cast
 | ||||
|     pub aabb: Aabb3d, | ||||
| } | ||||
| 
 | ||||
| impl AabbCast3d { | ||||
|     /// Construct an [`AabbCast3d`] from an [`Aabb3d`], origin, [`Direction3d`], and max distance.
 | ||||
|     pub fn new(aabb: Aabb3d, origin: Vec3, direction: Direction3d, max: f32) -> Self { | ||||
|         Self::from_ray(aabb, Ray3d { origin, direction }, max) | ||||
|     } | ||||
| 
 | ||||
|     /// Construct an [`AabbCast3d`] from an [`Aabb3d`], [`Ray3d`], and max distance.
 | ||||
|     pub fn from_ray(aabb: Aabb3d, ray: Ray3d, max: f32) -> Self { | ||||
|         Self { | ||||
|             ray: RayTest3d::from_ray(ray, max), | ||||
|             aabb, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get the distance at which the [`Aabb3d`]s collide, if at all.
 | ||||
|     pub fn aabb_collision_at(&self, mut aabb: Aabb3d) -> Option<f32> { | ||||
|         aabb.min -= self.aabb.max; | ||||
|         aabb.max -= self.aabb.min; | ||||
|         self.ray.aabb_intersection_at(&aabb) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl IntersectsVolume<Aabb3d> for AabbCast3d { | ||||
|     fn intersects(&self, volume: &Aabb3d) -> bool { | ||||
|         self.aabb_collision_at(*volume).is_some() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// An intersection test that casts a [`BoundingSphere`] along a ray.
 | ||||
| #[derive(Debug)] | ||||
| pub struct BoundingSphereCast { | ||||
|     /// The ray along which to cast the bounding volume
 | ||||
|     pub ray: RayTest3d, | ||||
|     /// The sphere that is being cast
 | ||||
|     pub sphere: BoundingSphere, | ||||
| } | ||||
| 
 | ||||
| impl BoundingSphereCast { | ||||
|     /// Construct a [`BoundingSphereCast`] from a [`BoundingSphere`], origin, [`Direction3d`], and max distance.
 | ||||
|     pub fn new(sphere: BoundingSphere, origin: Vec3, direction: Direction3d, max: f32) -> Self { | ||||
|         Self::from_ray(sphere, Ray3d { origin, direction }, max) | ||||
|     } | ||||
| 
 | ||||
|     /// Construct a [`BoundingSphereCast`] from a [`BoundingSphere`], [`Ray3d`], and max distance.
 | ||||
|     pub fn from_ray(sphere: BoundingSphere, ray: Ray3d, max: f32) -> Self { | ||||
|         Self { | ||||
|             ray: RayTest3d::from_ray(ray, max), | ||||
|             sphere, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get the distance at which the [`BoundingSphere`]s collide, if at all.
 | ||||
|     pub fn sphere_collision_at(&self, mut sphere: BoundingSphere) -> Option<f32> { | ||||
|         sphere.center -= self.sphere.center; | ||||
|         sphere.sphere.radius += self.sphere.radius(); | ||||
|         self.ray.sphere_intersection_at(&sphere) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl IntersectsVolume<BoundingSphere> for BoundingSphereCast { | ||||
|     fn intersects(&self, volume: &BoundingSphere) -> bool { | ||||
|         self.sphere_collision_at(*volume).is_some() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| @ -346,4 +420,138 @@ mod tests { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_aabb_cast_hits() { | ||||
|         for (test, volume, expected_distance) in &[ | ||||
|             ( | ||||
|                 // Hit the center of the aabb, that a ray would've also hit
 | ||||
|                 AabbCast3d::new( | ||||
|                     Aabb3d::new(Vec3::ZERO, Vec3::ONE), | ||||
|                     Vec3::ZERO, | ||||
|                     Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb3d::new(Vec3::Y * 5., Vec3::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the center of the aabb, but from the other side
 | ||||
|                 AabbCast3d::new( | ||||
|                     Aabb3d::new(Vec3::ZERO, Vec3::ONE), | ||||
|                     Vec3::Y * 10., | ||||
|                     -Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb3d::new(Vec3::Y * 5., Vec3::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the edge of the aabb, that a ray would've missed
 | ||||
|                 AabbCast3d::new( | ||||
|                     Aabb3d::new(Vec3::ZERO, Vec3::ONE), | ||||
|                     Vec3::X * 1.5, | ||||
|                     Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb3d::new(Vec3::Y * 5., Vec3::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the edge of the aabb, by casting an off-center AABB
 | ||||
|                 AabbCast3d::new( | ||||
|                     Aabb3d::new(Vec3::X * -2., Vec3::ONE), | ||||
|                     Vec3::X * 3., | ||||
|                     Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 Aabb3d::new(Vec3::Y * 5., Vec3::ONE), | ||||
|                 3., | ||||
|             ), | ||||
|         ] { | ||||
|             let case = format!( | ||||
|                 "Case:\n  Test: {:?}\n  Volume: {:?}\n  Expected distance: {:?}", | ||||
|                 test, volume, expected_distance | ||||
|             ); | ||||
|             assert!(test.intersects(volume), "{}", case); | ||||
|             let actual_distance = test.aabb_collision_at(*volume).unwrap(); | ||||
|             assert!( | ||||
|                 (actual_distance - expected_distance).abs() < EPSILON, | ||||
|                 "{}\n  Actual distance: {}", | ||||
|                 case, | ||||
|                 actual_distance | ||||
|             ); | ||||
| 
 | ||||
|             let inverted_ray = | ||||
|                 RayTest3d::new(test.ray.ray.origin, -test.ray.ray.direction, test.ray.max); | ||||
|             assert!(!inverted_ray.intersects(volume), "{}", case); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_sphere_cast_hits() { | ||||
|         for (test, volume, expected_distance) in &[ | ||||
|             ( | ||||
|                 // Hit the center of the bounding sphere, that a ray would've also hit
 | ||||
|                 BoundingSphereCast::new( | ||||
|                     BoundingSphere::new(Vec3::ZERO, 1.), | ||||
|                     Vec3::ZERO, | ||||
|                     Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingSphere::new(Vec3::Y * 5., 1.), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the center of the bounding sphere, but from the other side
 | ||||
|                 BoundingSphereCast::new( | ||||
|                     BoundingSphere::new(Vec3::ZERO, 1.), | ||||
|                     Vec3::Y * 10., | ||||
|                     -Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingSphere::new(Vec3::Y * 5., 1.), | ||||
|                 3., | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the bounding sphere off-center, that a ray would've missed
 | ||||
|                 BoundingSphereCast::new( | ||||
|                     BoundingSphere::new(Vec3::ZERO, 1.), | ||||
|                     Vec3::X * 1.5, | ||||
|                     Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingSphere::new(Vec3::Y * 5., 1.), | ||||
|                 3.677, | ||||
|             ), | ||||
|             ( | ||||
|                 // Hit the bounding sphere off-center, by casting a sphere that is off-center
 | ||||
|                 BoundingSphereCast::new( | ||||
|                     BoundingSphere::new(Vec3::X * -1.5, 1.), | ||||
|                     Vec3::X * 3., | ||||
|                     Direction3d::Y, | ||||
|                     90., | ||||
|                 ), | ||||
|                 BoundingSphere::new(Vec3::Y * 5., 1.), | ||||
|                 3.677, | ||||
|             ), | ||||
|         ] { | ||||
|             let case = format!( | ||||
|                 "Case:\n  Test: {:?}\n  Volume: {:?}\n  Expected distance: {:?}", | ||||
|                 test, volume, expected_distance | ||||
|             ); | ||||
|             assert!(test.intersects(volume), "{}", case); | ||||
|             let actual_distance = test.sphere_collision_at(*volume).unwrap(); | ||||
|             assert!( | ||||
|                 (actual_distance - expected_distance).abs() < EPSILON, | ||||
|                 "{}\n  Actual distance: {}", | ||||
|                 case, | ||||
|                 actual_distance | ||||
|             ); | ||||
| 
 | ||||
|             let inverted_ray = | ||||
|                 RayTest3d::new(test.ray.ray.origin, -test.ray.ray.direction, test.ray.max); | ||||
|             assert!(!inverted_ray.intersects(volume), "{}", case); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 NiseVoid
						NiseVoid