Reworked ray-sphere intersection which was failing tests

This commit is contained in:
Matthew Gordon 2019-11-13 17:25:57 -05:00
parent d9af6dad94
commit 700de75337
2 changed files with 15 additions and 10 deletions

View File

@ -128,6 +128,7 @@ mod tests {
Some(IntersectionInfo { Some(IntersectionInfo {
location, location,
distance: _, distance: _,
normal: _,
}) => location, }) => location,
None => panic!(), None => panic!(),
}; };

View File

@ -45,23 +45,26 @@ 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>> {
// 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 = (self.centre - ray.origin).dot(&ray.direction);
let delta_squared = if t0 < T::zero() {
t0 * t0 - ((ray.origin - self.centre).norm_squared() - self.radius * self.radius); // Sphere is behind ray origin
if delta_squared > self.radius {
//No initersection
return None; return None;
} }
let delta = delta_squared.sqrt(); let radius_squared = self.radius*self.radius;
let distance = if (self.centre - ray.origin).norm() <= self.radius { // Squared distance between ray origin and sphere centre
let d0_squared = (ray.origin - self.centre).norm_squared();
// Squared distance petween p0 and sphere centre
let p0_dist_from_centre_squared = d0_squared - t0*t0;
if p0_dist_from_centre_squared > radius_squared {
// Sphere is in front of ray but ray misses
return None;
}
let delta = (radius_squared - p0_dist_from_centre_squared).sqrt();
let distance = if (self.centre - ray.origin).norm_squared() <= radius_squared {
// radius origin is inside sphere // radius origin is inside sphere
t0 + delta t0 + delta
} else { } else {
t0 - delta t0 - delta
}; };
if distance < T::zero() {
// Sphere is behind ray origin
return None;
};
let location = ray.point_at(distance); let location = ray.point_at(distance);
let normal = (location - self.centre).normalize(); let normal = (location - self.centre).normalize();
Some(IntersectionInfo { Some(IntersectionInfo {
@ -200,6 +203,7 @@ mod tests {
Some(IntersectionInfo { Some(IntersectionInfo {
distance: _, distance: _,
location, location,
normal: _,
}) => assert!((location.x - (-5.0f64)).abs() < 0.0000000001), }) => assert!((location.x - (-5.0f64)).abs() < 0.0000000001),
None => panic!(), None => panic!(),
} }