BVH4 is just a skeleton (duplicated BVH) right now. But BBox4 is complete (pending testing).
165 lines
5.3 KiB
Rust
165 lines
5.3 KiB
Rust
#![allow(dead_code)]
|
|
|
|
use mem_arena::MemArena;
|
|
|
|
use algorithm::partition;
|
|
use bbox::BBox;
|
|
use boundable::Boundable;
|
|
use lerp::lerp_slice;
|
|
use ray::AccelRay;
|
|
|
|
use super::bvh_base::{BVHBase, BVHBaseNode, BVH_MAX_DEPTH};
|
|
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct BVH4<'a> {
|
|
root: Option<&'a BVH4Node<'a>>,
|
|
depth: usize,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
enum BVH4Node<'a> {
|
|
Internal {
|
|
bounds: &'a [BBox],
|
|
children: (&'a BVH4Node<'a>, &'a BVH4Node<'a>),
|
|
split_axis: u8,
|
|
},
|
|
|
|
Leaf {
|
|
bounds: &'a [BBox],
|
|
object_range: (usize, usize),
|
|
},
|
|
}
|
|
|
|
impl<'a> BVH4<'a> {
|
|
pub fn from_objects<'b, T, F>(arena: &'a MemArena,
|
|
objects: &mut [T],
|
|
objects_per_leaf: usize,
|
|
bounder: F)
|
|
-> BVH4<'a>
|
|
where F: 'b + Fn(&T) -> &'b [BBox]
|
|
{
|
|
if objects.len() == 0 {
|
|
BVH4 {
|
|
root: None,
|
|
depth: 0,
|
|
}
|
|
} else {
|
|
let base = BVHBase::from_objects(objects, objects_per_leaf, bounder);
|
|
|
|
BVH4 {
|
|
root: Some(BVH4::construct_from_base(arena, &base, base.root_node_index())),
|
|
depth: base.depth,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn tree_depth(&self) -> usize {
|
|
self.depth
|
|
}
|
|
|
|
pub fn traverse<T, F>(&self, rays: &mut [AccelRay], objects: &[T], mut obj_ray_test: F)
|
|
where F: FnMut(&T, &mut [AccelRay])
|
|
{
|
|
match self.root {
|
|
None => {}
|
|
|
|
Some(root) => {
|
|
// +2 of max depth for root and last child
|
|
let mut node_stack = [root; BVH_MAX_DEPTH + 2];
|
|
let mut ray_i_stack = [rays.len(); BVH_MAX_DEPTH + 2];
|
|
let mut stack_ptr = 1;
|
|
|
|
while stack_ptr > 0 {
|
|
match node_stack[stack_ptr] {
|
|
&BVH4Node::Internal { bounds, children, split_axis } => {
|
|
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|
|
(!r.is_done()) && lerp_slice(bounds, r.time).intersect_accel_ray(r)
|
|
});
|
|
if part > 0 {
|
|
node_stack[stack_ptr] = children.0;
|
|
node_stack[stack_ptr + 1] = children.1;
|
|
ray_i_stack[stack_ptr] = part;
|
|
ray_i_stack[stack_ptr + 1] = part;
|
|
if rays[0].dir_inv.get_n(split_axis as usize).is_sign_positive() {
|
|
node_stack.swap(stack_ptr, stack_ptr + 1);
|
|
}
|
|
stack_ptr += 1;
|
|
} else {
|
|
stack_ptr -= 1;
|
|
}
|
|
}
|
|
|
|
&BVH4Node::Leaf { bounds, object_range } => {
|
|
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|
|
(!r.is_done()) && lerp_slice(bounds, r.time).intersect_accel_ray(r)
|
|
});
|
|
if part > 0 {
|
|
for obj in &objects[object_range.0..object_range.1] {
|
|
obj_ray_test(obj, &mut rays[..part]);
|
|
}
|
|
}
|
|
|
|
stack_ptr -= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn construct_from_base(arena: &'a MemArena,
|
|
base: &BVHBase,
|
|
node_index: usize)
|
|
-> &'a mut BVH4Node<'a> {
|
|
match &base.nodes[node_index] {
|
|
&BVHBaseNode::Internal { bounds_range, children_indices, split_axis } => {
|
|
let mut node = unsafe { arena.alloc_uninitialized::<BVH4Node>() };
|
|
|
|
let bounds = arena.copy_slice(&base.bounds[bounds_range.0..bounds_range.1]);
|
|
let child1 = BVH4::construct_from_base(arena, base, children_indices.0);
|
|
let child2 = BVH4::construct_from_base(arena, base, children_indices.1);
|
|
|
|
*node = BVH4Node::Internal {
|
|
bounds: bounds,
|
|
children: (child1, child2),
|
|
split_axis: split_axis,
|
|
};
|
|
|
|
return node;
|
|
}
|
|
|
|
&BVHBaseNode::Leaf { bounds_range, object_range } => {
|
|
let mut node = unsafe { arena.alloc_uninitialized::<BVH4Node>() };
|
|
let bounds = arena.copy_slice(&base.bounds[bounds_range.0..bounds_range.1]);
|
|
|
|
*node = BVH4Node::Leaf {
|
|
bounds: bounds,
|
|
object_range: object_range,
|
|
};
|
|
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lazy_static! {
|
|
static ref DEGENERATE_BOUNDS: [BBox; 1] = [BBox::new()];
|
|
}
|
|
|
|
impl<'a> Boundable for BVH4<'a> {
|
|
fn bounds<'b>(&'b self) -> &'b [BBox] {
|
|
match self.root {
|
|
None => &DEGENERATE_BOUNDS[..],
|
|
Some(root) => {
|
|
match root {
|
|
&BVH4Node::Internal { bounds, .. } => bounds,
|
|
|
|
&BVH4Node::Leaf { bounds, .. } => bounds,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|