Fix failed intersection when ray origin is insode sphere

Added unit test which detected a false miss when the sphere centre
is behind the ray origin but the ray origin is inside the sphere.
This commit is contained in:
Matthew Gordon 2019-11-13 17:45:33 -05:00
parent 3c24a084b9
commit c144780fce
1 changed files with 14 additions and 5 deletions

View File

@ -43,13 +43,15 @@ impl<T: RealField> Sphere<T> {
impl<T: RealField> Intersect<T> for Sphere<T> { impl<T: RealField> Intersect<T> for Sphere<T> {
fn intersect(&self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> { fn intersect(&self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
let ray_origin_to_sphere_centre = self.centre - ray.origin;
let radius_squared = self.radius * self.radius;
let is_inside_sphere = ray_origin_to_sphere_centre.norm_squared() <= radius_squared;
// t0/p0 is the point on the ray that's closest to the centre of the sphere // t0/p0 is the point on the ray that's closest to the centre of the sphere
let t0 = (self.centre - ray.origin).dot(&ray.direction); let t0 = ray_origin_to_sphere_centre.dot(&ray.direction);
if t0 < T::zero() { if !is_inside_sphere && t0 < T::zero() {
// Sphere is behind ray origin // Sphere is behind ray origin
return None; return None;
} }
let radius_squared = self.radius*self.radius;
// Squared distance between ray origin and sphere centre // Squared distance between ray origin and sphere centre
let d0_squared = (ray.origin - self.centre).norm_squared(); let d0_squared = (ray.origin - self.centre).norm_squared();
// Squared distance petween p0 and sphere centre // Squared distance petween p0 and sphere centre
@ -59,7 +61,7 @@ impl<T: RealField> Intersect<T> for Sphere<T> {
return None; return None;
} }
let delta = (radius_squared - p0_dist_from_centre_squared).sqrt(); let delta = (radius_squared - p0_dist_from_centre_squared).sqrt();
let distance = if (self.centre - ray.origin).norm_squared() <= radius_squared { let distance = if is_inside_sphere {
// radius origin is inside sphere // radius origin is inside sphere
t0 + delta t0 + delta
} else { } else {
@ -188,6 +190,13 @@ mod tests {
assert_matches!(s.intersect(&r), None); assert_matches!(s.intersect(&r), None);
} }
#[test]
fn ray_intersects_sphere_when_origin_is_inside() {
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
let s = Sphere::new(Vector3::new(1.5, 1.5, 2.0), 5.0);
assert_matches!(s.intersect(&r), Some(_));
}
#[test] #[test]
fn ray_intersects_plane() { fn ray_intersects_plane() {
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(-1.0, 0.0, 1.0)); let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(-1.0, 0.0, 1.0));