diff --git a/rtiow/renderer/src/aabb.rs b/rtiow/renderer/src/aabb.rs index 0aded58..f03c164 100644 --- a/rtiow/renderer/src/aabb.rs +++ b/rtiow/renderer/src/aabb.rs @@ -71,6 +71,8 @@ impl AABB { self.bounds[1] } + // TODO(wathiede): implement branchless https://tavianator.com/cgit/dimension.git/tree/libdimension/bvh/bvh.c#n194 + pub fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> bool { self.hit_simd(r, t_min, t_max) //self.hit_naive(r, t_min, t_max) @@ -152,7 +154,7 @@ impl AABB { unsafe { use std::arch::x86_64::*; let o4 = _mm_set_ps(0., r.origin.z, r.origin.y, r.origin.x); - let d4 = _mm_set_ps(0., r.direction.z, r.direction.y, r.direction.x); + let d4 = _mm_set_ps(0., r.inv_direction.z, r.inv_direction.y, r.inv_direction.x); let bmin4 = _mm_set_ps(0., self.min().z, self.min().y, self.min().x); let bmax4 = _mm_set_ps(0., self.max().z, self.max().y, self.max().x); let mask4 = _mm_cmpeq_ps(_mm_setzero_ps(), _mm_set_ps(1., 0., 0., 0.)); @@ -162,10 +164,9 @@ impl AABB { let vmin4 = _mm_min_ps(t1, t2); let vmax4: (f32, f32, f32, f32) = std::mem::transmute(vmax4); let vmin4: (f32, f32, f32, f32) = std::mem::transmute(vmin4); - let tmax = min(vmax4.0, min(vmax4.1, vmax4.2)); - let tmin = max(vmin4.0, max(vmin4.1, vmin4.2)); - //tmax >= tmin && tmin < r.time && tmax > t_min - t_min <= tmin && tmin <= t_max + let tmax = min(min(vmax4.0, min(vmax4.1, vmax4.2)), t_max); + let tmin = max(max(vmin4.0, max(vmin4.1, vmin4.2)), t_min); + tmin <= tmax } } @@ -209,34 +210,91 @@ mod tests { macro_rules! hit_test { ($($name:ident,)*) => { - mod hit { - use super::*; - $( - #[test] - fn $name() { - let t_min = 0.001; - let t_max = f32::MAX; - let bb = AABB::new([1., -1., -1.], [3., 1., 1.]); - // Hit - let r = Ray::new([0., 0., 0.], [1., 0., 0.], 0.5); - assert!(bb.$name(r, t_min, t_max)); + $( + mod $name { + use super::*; + const T_MIN: f32 = 0.001; + const T_MAX: f32 = f32::MAX; + + fn test_bb() -> AABB { + AABB::new([-1., -1., -1.], [1., 1., 1.]) } - )* - } - mod miss { - use super::*; - $( + #[test] - fn $name() { - let t_min = 0.001; - let t_max = f32::MAX; - let bb = AABB::new([1., -1., -1.], [3., 1., 1.]); - // Miss - let r = Ray::new([0., 0., 0.], [-1., 0., 0.], 0.5); - assert!(!bb.$name(r, t_min, t_max)); + fn hit_front() { + let bb = test_bb(); + let r = Ray::new([-2., 0., 0.], [1., 0., 0.], 0.5); + assert!(bb.$name(r, T_MIN, T_MAX)); } - )* - } + #[test] + fn hit_back() { + let bb = test_bb(); + let r = Ray::new([2., 0., 0.], [-1., 0., 0.], 0.5); + assert!(bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn hit_top() { + let bb = test_bb(); + let r = Ray::new([0., 2., 0.], [0., -1., 0.], 0.5); + assert!(bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn hit_bottom() { + let bb = test_bb(); + let r = Ray::new([0., -2., 0.], [0., 1., 0.], 0.5); + assert!(bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn hit_left() { + let bb = test_bb(); + let r = Ray::new([0., 0., -2.], [0., 0., 1.], 0.5); + assert!(bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn hit_right() { + let bb = test_bb(); + let r = Ray::new([0., 0., 2.], [0., 0., -1.], 0.5); + assert!(bb.$name(r, T_MIN, T_MAX)); + } + + #[test] + fn miss_front() { + let bb = test_bb(); + let r = Ray::new([0., 1.1, -1.1], [0., -1., 0.], 0.5); + assert!(!bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn miss_back() { + let bb = test_bb(); + let r = Ray::new([0., 1.1, 1.1], [0., -1., 0.], 0.5); + assert!(!bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn miss_top() { + let bb = test_bb(); + let r = Ray::new([0., 1.1, -1.1], [0., 0., 1.], 0.5); + assert!(!bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn miss_bottom() { + let bb = test_bb(); + let r = Ray::new([0., -1.1, -1.1], [0., 0., 1.], 0.5); + assert!(!bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn miss_left() { + let bb = test_bb(); + let r = Ray::new([-1.1, 0., -1.1], [0., 0., 1.], 0.5); + assert!(!bb.$name(r, T_MIN, T_MAX)); + } + #[test] + fn miss_right() { + let bb = test_bb(); + let r = Ray::new([1.1, 0., -1.1], [0., 0., 1.], 0.5); + assert!(!bb.$name(r, T_MIN, T_MAX)); + } + } + )* } } diff --git a/rtiow/renderer/src/ray.rs b/rtiow/renderer/src/ray.rs index f250646..72bc4b7 100644 --- a/rtiow/renderer/src/ray.rs +++ b/rtiow/renderer/src/ray.rs @@ -5,6 +5,9 @@ pub struct Ray { pub origin: Vec3, pub direction: Vec3, pub time: f32, + + // Precache 1/direction, a single ray intersects multiple AABB's, and divides are more + // expensive than multiplies. pub inv_direction: Vec3, pub sign: [usize; 3], } @@ -14,7 +17,7 @@ impl Ray { where V: Into, { - let direction = direction.into(); + let direction: Vec3 = direction.into(); let origin = origin.into(); let inv = 1. / direction; Ray { diff --git a/rtiow/renderer/src/scenes/stltest.rs b/rtiow/renderer/src/scenes/stltest.rs index a11803a..c2d2e68 100644 --- a/rtiow/renderer/src/scenes/stltest.rs +++ b/rtiow/renderer/src/scenes/stltest.rs @@ -41,7 +41,9 @@ pub fn new(opt: &Opt) -> Scene { }; let stl_cube = STL::parse( - BufReader::new(Cursor::new(include_bytes!("../../stls/20mm cube.stl"))), + BufReader::new(Cursor::new(include_bytes!( + "../../stls/stanford_dragon-lowres.stl" + ))), false, ) .expect("failed to parse cube"); @@ -106,7 +108,8 @@ pub fn new(opt: &Opt) -> Scene { &stl_cube, Lambertian::new(ConstantTexture::new(Vec3::new(0.6, 0.6, 0.6))), ), - 200., + //1., + 250., )), ]; let world: Box = if opt.use_accel {