diff --git a/clovers/src/aabb.rs b/clovers/src/aabb.rs index aaa3d191..35434826 100644 --- a/clovers/src/aabb.rs +++ b/clovers/src/aabb.rs @@ -43,13 +43,56 @@ impl AABB { #[must_use] pub fn hit(&self, ray: &Ray, mut tmin: Float, mut tmax: Float) -> bool { // TODO: Create an improved hit method with more robust handling of zeroes. See https://github.com/RayTracing/raytracing.github.io/issues/927 + // Both methods below are susceptible for NaNs and infinities, and have subtly different edge cases. + + // "New method" + // for axis in 0..3 { + // let a = (self.axis(axis).min - ray.origin[axis]) / ray.direction[axis]; + // let b = (self.axis(axis).max - ray.origin[axis]) / ray.direction[axis]; + // let t0: Float = a.min(b); + // let t1: Float = a.max(b); + // tmin = t0.max(tmin); + // tmax = t1.min(tmax); + // if tmax <= tmin { + // return false; + // } + // } + + // "Old method" + // for axis in 0..3 { + // let invd = 1.0 / ray.direction[axis]; + // let mut t0: Float = (self.axis(axis).min - ray.origin[axis]) * invd; + // let mut t1: Float = (self.axis(axis).max - ray.origin[axis]) * invd; + // if invd < 0.0 { + // core::mem::swap(&mut t0, &mut t1); + // } + // tmin = if t0 > tmin { t0 } else { tmin }; + // tmax = if t1 < tmax { t1 } else { tmax }; + // if tmax <= tmin { + // return false; + // } + // } + + // "My adjusted method" - possibly more zero-resistant? + // TODO: validate for axis in 0..3 { - let a = (self.axis(axis).min - ray.origin[axis]) / ray.direction[axis]; - let b = (self.axis(axis).max - ray.origin[axis]) / ray.direction[axis]; - let t0: Float = a.min(b); - let t1: Float = a.max(b); - tmin = t0.max(tmin); - tmax = t1.min(tmax); + // If ray direction component is 0, invd becomes infinity. + // Ignore? False positive hit for aabb is probably better than false negative; the actual object can still be hit more accurately + let invd = 1.0 / ray.direction[axis]; + if !invd.is_normal() { + continue; + } + // If the value in parenthesis ends up as zero, 0*inf can be NaN + let mut t0: Float = (self.axis(axis).min - ray.origin[axis]) * invd; + let mut t1: Float = (self.axis(axis).max - ray.origin[axis]) * invd; + if !t0.is_normal() || !t1.is_normal() { + continue; + } + if invd < 0.0 { + core::mem::swap(&mut t0, &mut t1); + } + tmin = if t0 > tmin { t0 } else { tmin }; + tmax = if t1 < tmax { t1 } else { tmax }; if tmax <= tmin { return false; }