From 573c5da5ab068ad15327d170d6fcbc160ae600d1 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Thu, 13 Apr 2017 22:44:34 -0700 Subject: [PATCH] Got BVH4 working. Woo hoo! --- src/accel/bvh4.rs | 58 +++++++++++++++++------------------- src/bitstack.rs | 28 +++++++---------- src/float4.rs | 2 +- src/scene/assembly.rs | 14 ++++----- src/surface/triangle_mesh.rs | 12 ++++---- 5 files changed, 53 insertions(+), 61 deletions(-) diff --git a/src/accel/bvh4.rs b/src/accel/bvh4.rs index b2c45ae..88f5a64 100644 --- a/src/accel/bvh4.rs +++ b/src/accel/bvh4.rs @@ -98,47 +98,41 @@ impl<'a> BVH4<'a> { TRAVERSAL_TABLE[ray_code as usize][traversal_code as usize] }; - let mut all_hits = 0; // Accumulate + // Ray testing let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| { if (!r.is_done()) && (first_loop || r.trav_stack.pop()) { let hits = lerp_slice(bounds, r.time) .intersect_accel_ray(r) .to_bitmask(); - all_hits |= hits; - // Push hit bits onto ray's traversal stack - let mut shuffled_hits = 0; - for i in 0..3 { - let ii = (node_order_code >> (i * 2)) & 3; - shuffled_hits |= ((hits >> ii) & 1) << i; + if hits != 0 { + // Push hit bits onto ray's traversal stack + let mut shuffled_hits = 0; + for i in 0..children.len() { + let ii = (node_order_code >> (i * 2)) & 3; + shuffled_hits |= ((hits >> ii) & 1) << i; + } + r.trav_stack.push_n(shuffled_hits, children.len() as u8); + + true + } else { + false } - r.trav_stack.push_3(shuffled_hits); - - true } else { false } }); - if part > 0 { - node_stack[stack_ptr] = { - Some(&children[(node_order_code & 3) as usize]) - }; - node_stack[stack_ptr + 1] = { - Some(&children[((node_order_code >> 2) & 3) as usize]) - }; - node_stack[stack_ptr + 2] = if children.len() > 2 { - Some(&children[((node_order_code >> 4) & 3) as usize]) - } else { - None - }; - node_stack[stack_ptr + 3] = if children.len() > 3 { - Some(&children[((node_order_code >> 6) & 3) as usize]) - } else { - None - }; - ray_i_stack[stack_ptr] = part; - ray_i_stack[stack_ptr + 1] = part; + // Update stack based on ray testing results + if part > 0 { + for i in 0..children.len() { + let inv_i = (children.len() - 1) - i; + node_stack[stack_ptr + i] = + Some(&children[((node_order_code >> (inv_i * 2)) & 3) as + usize]); + ray_i_stack[stack_ptr + i] = part; + } + stack_ptr += children.len() - 1; } else { stack_ptr -= 1; @@ -298,7 +292,11 @@ impl<'a> BVH4<'a> { }; calc_traversal_code(split_axis, split_axis_l.unwrap_or(split_axis_r.unwrap_or(0)), - split_axis_r.unwrap_or(0), + if child_count == 4 { + split_axis_r.unwrap() + } else { + 0 + }, topology_code) }; *fill_node = BVH4Node::Internal { diff --git a/src/bitstack.rs b/src/bitstack.rs index afe28e4..0d4f95e 100644 --- a/src/bitstack.rs +++ b/src/bitstack.rs @@ -24,20 +24,24 @@ impl BitStack128 { self.data.0 |= value as u64; } - /// Push 3 bits onto the top of the stack. The input + /// Push n bits onto the top of the stack. The input /// bits are passed as an integer, with the bit that /// will be on top in the least significant digit, and /// the rest following in order from there. /// /// Note that unless you are running a debug build, no - /// effort is made to verify that only the first three + /// effort is made to verify that only the first n /// bits of the passed value are used. So if other /// bits are non-zero this will produce incorrect results. - pub fn push_3(&mut self, value: u8) { - debug_assert!((self.data.1 >> (size_of::() - 3)) == 0); // Verify no stack overflow - debug_assert!(value & (!((1 << 3) - 1)) == 0); // Verify no bits outside of the 3-bit range - self.data.1 = (self.data.1 << 3) | (self.data.0 >> (size_of::() - 3)); - self.data.0 <<= 3; + pub fn push_n(&mut self, value: u8, count: u8) { + // Verify no bitstack overflow + debug_assert!((self.data.1 >> (size_of::() - count as usize)) == 0); + // Verify no bits outside of the n-bit range + debug_assert!(value & (!((1 << count) - 1)) == 0); + + self.data.1 = (self.data.1 << count as usize) | + (self.data.0 >> (size_of::() - count as usize)); + self.data.0 <<= count as u64; self.data.0 |= value as u64; } @@ -61,16 +65,6 @@ impl BitStack128 { return b; } - /// Pop the top n bits off the stack, returning only the first - /// one. - pub fn pop_1_remove_n(&mut self, n: usize) -> bool { - debug_assert!(n < size_of::()); // Can't pop more than we have - let b = (self.data.0 & 1) != 0; - self.data.0 = (self.data.0 >> n) | (self.data.1 << (size_of::() - n)); - self.data.1 >>= n; - return b; - } - /// Read the top bit of the stack without popping it. pub fn peek(&self) -> bool { (self.data.0 & 1) != 0 diff --git a/src/float4.rs b/src/float4.rs index ad4f7da..b340034 100644 --- a/src/float4.rs +++ b/src/float4.rs @@ -520,7 +520,7 @@ impl Bool4 { } pub fn to_bitmask(&self) -> u8 { - (self.get_0() as u8) & ((self.get_1() as u8) << 1) & ((self.get_2() as u8) << 2) & + (self.get_0() as u8) | ((self.get_1() as u8) << 1) | ((self.get_2() as u8) << 2) | ((self.get_3() as u8) << 3) } } diff --git a/src/scene/assembly.rs b/src/scene/assembly.rs index 1883640..5c0a271 100644 --- a/src/scene/assembly.rs +++ b/src/scene/assembly.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use mem_arena::MemArena; use accel::{LightAccel, LightTree}; -use accel::BVH; +use accel::BVH4; use bbox::{BBox, transform_bbox_slice_from}; use boundable::Boundable; use color::SpectralSample; @@ -28,7 +28,7 @@ pub struct Assembly<'a> { pub assemblies: &'a [Assembly<'a>], // Object accel - pub object_accel: BVH<'a>, + pub object_accel: BVH4<'a>, // Light accel pub light_accel: LightTree<'a>, @@ -231,10 +231,10 @@ impl<'a> AssemblyBuilder<'a> { let (bis, bbs) = self.instance_bounds(); // Build object accel - let object_accel = BVH::from_objects(self.arena, - &mut self.instances[..], - 1, - |inst| &bbs[bis[inst.id]..bis[inst.id + 1]]); + let object_accel = BVH4::from_objects(self.arena, + &mut self.instances[..], + 1, + |inst| &bbs[bis[inst.id]..bis[inst.id + 1]]); // Get list of instances that are for light sources or assemblies that contain light // sources. @@ -288,7 +288,7 @@ impl<'a> AssemblyBuilder<'a> { /// Returns a pair of vectors with the bounds of all instances. - /// This is used for building the assembly's BVH. + /// This is used for building the assembly's BVH4. fn instance_bounds(&self) -> (Vec, Vec) { let mut indices = vec![0]; let mut bounds = Vec::new(); diff --git a/src/surface/triangle_mesh.rs b/src/surface/triangle_mesh.rs index e3cc094..eae0995 100644 --- a/src/surface/triangle_mesh.rs +++ b/src/surface/triangle_mesh.rs @@ -2,7 +2,7 @@ use mem_arena::MemArena; -use accel::BVH; +use accel::BVH4; use bbox::BBox; use boundable::Boundable; use color::XYZ; @@ -20,7 +20,7 @@ pub struct TriangleMesh<'a> { time_samples: usize, geo: &'a [(Point, Point, Point)], indices: &'a [usize], - accel: BVH<'a>, + accel: BVH4<'a>, } impl<'a> TriangleMesh<'a> { @@ -44,10 +44,10 @@ impl<'a> TriangleMesh<'a> { bounds }; - let accel = BVH::from_objects(arena, - &mut indices[..], - 3, - |tri_i| &bounds[*tri_i..(*tri_i + time_samples)]); + let accel = BVH4::from_objects(arena, + &mut indices[..], + 3, + |tri_i| &bounds[*tri_i..(*tri_i + time_samples)]); TriangleMesh { time_samples: time_samples,