From d3b3a50a4d4c9d97fed0b426ee04e5db60fd7bab Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Mon, 10 Apr 2017 00:03:49 -0700 Subject: [PATCH] LightTree and Assemblies use MemArena now. --- src/accel/bvh.rs | 4 +- src/accel/light_tree.rs | 204 ++++++++++++++++++++++------------------ src/scene/assembly.rs | 16 ++-- 3 files changed, 121 insertions(+), 103 deletions(-) diff --git a/src/accel/bvh.rs b/src/accel/bvh.rs index a0636d9..e0f2fb0 100644 --- a/src/accel/bvh.rs +++ b/src/accel/bvh.rs @@ -43,7 +43,7 @@ impl<'a> BVH<'a> { -> BVH<'a> where F: 'b + Fn(&T) -> &'b [BBox] { - let mut builder = BVHBuilder::new_empty(); + let mut builder = BVHBuilder::new(); builder.recursive_build(0, 0, objects_per_leaf, objects, &bounder); @@ -129,7 +129,7 @@ struct BVHBuilder { } impl BVHBuilder { - fn new_empty() -> BVHBuilder { + fn new() -> BVHBuilder { BVHBuilder { nodes: Vec::new(), bounds: Vec::new(), diff --git a/src/accel/light_tree.rs b/src/accel/light_tree.rs index 3124b87..5bdb668 100644 --- a/src/accel/light_tree.rs +++ b/src/accel/light_tree.rs @@ -1,3 +1,5 @@ +use mem_arena::MemArena; + use algorithm::merge_slices_append; use bbox::BBox; use lerp::lerp_slice; @@ -8,15 +10,14 @@ use super::LightAccel; use super::objects_split::sah_split; -#[derive(Debug)] -pub struct LightTree { - nodes: Vec, - bounds: Vec, +#[derive(Copy, Clone, Debug)] +pub struct LightTree<'a> { + nodes: &'a [Node], + bounds: &'a [BBox], depth: usize, - bounds_cache: Vec, } -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] struct Node { is_leaf: bool, bounds_range: (usize, usize), @@ -24,100 +25,26 @@ struct Node { child_index: usize, } -impl LightTree { - pub fn from_objects<'a, T, F>(objects: &mut [T], info_getter: F) -> LightTree - where F: 'a + Fn(&T) -> (&'a [BBox], f32) +impl<'a> LightTree<'a> { + pub fn from_objects<'b, T, F>(arena: &'a MemArena, + objects: &mut [T], + info_getter: F) + -> LightTree<'a> + where F: 'b + Fn(&T) -> (&'b [BBox], f32) { - let mut tree = LightTree { - nodes: Vec::new(), - bounds: Vec::new(), + let mut builder = LightTreeBuilder::new(); + builder.recursive_build(0, 0, objects, &info_getter); + + LightTree { + nodes: arena.copy_slice(&builder.nodes), + bounds: arena.copy_slice(&builder.bounds), depth: 0, - bounds_cache: Vec::new(), - }; - - tree.recursive_build(0, 0, objects, &info_getter); - tree.bounds_cache.clear(); - tree.bounds_cache.shrink_to_fit(); - - tree - } - - - fn recursive_build<'a, T, F>(&mut self, - offset: usize, - depth: usize, - objects: &mut [T], - info_getter: &F) - -> (usize, (usize, usize)) - where F: 'a + Fn(&T) -> (&'a [BBox], f32) - { - let me_index = self.nodes.len(); - - if objects.len() == 0 { - return (0, (0, 0)); - } else if objects.len() == 1 { - // Leaf node - let bi = self.bounds.len(); - let (obj_bounds, energy) = info_getter(&objects[0]); - self.bounds.extend(obj_bounds); - self.nodes.push(Node { - is_leaf: true, - bounds_range: (bi, self.bounds.len()), - energy: energy, - child_index: offset, - }); - - if self.depth < depth { - self.depth = depth; - } - - return (me_index, (bi, self.bounds.len())); - } else { - // Not a leaf node - self.nodes.push(Node { - is_leaf: false, - bounds_range: (0, 0), - energy: 0.0, - child_index: 0, - }); - - // Partition objects. - let (split_index, _) = sah_split(objects, &|obj_ref| info_getter(obj_ref).0); - - // Create child nodes - let (_, c1_bounds) = - self.recursive_build(offset, depth + 1, &mut objects[..split_index], info_getter); - let (c2_index, c2_bounds) = self.recursive_build(offset + split_index, - depth + 1, - &mut objects[split_index..], - info_getter); - - // Determine bounds - // TODO: do merging without the temporary vec. - let bi = self.bounds.len(); - let mut merged = Vec::new(); - merge_slices_append(&self.bounds[c1_bounds.0..c1_bounds.1], - &self.bounds[c2_bounds.0..c2_bounds.1], - &mut merged, - |b1, b2| *b1 | *b2); - self.bounds.extend(merged.drain(0..)); - - // Set node - let energy = self.nodes[me_index + 1].energy + self.nodes[c2_index].energy; - self.nodes[me_index] = Node { - is_leaf: false, - bounds_range: (bi, self.bounds.len()), - energy: energy, - child_index: c2_index, - }; - - return (me_index, (bi, self.bounds.len())); } } } -impl LightAccel for LightTree { +impl<'a> LightAccel for LightTree<'a> { fn select(&self, inc: Vector, pos: Point, @@ -207,3 +134,94 @@ impl LightAccel for LightTree { } } } + + +struct LightTreeBuilder { + nodes: Vec, + bounds: Vec, + depth: usize, + bounds_cache: Vec, +} + +impl LightTreeBuilder { + fn new() -> LightTreeBuilder { + LightTreeBuilder { + nodes: Vec::new(), + bounds: Vec::new(), + depth: 0, + bounds_cache: Vec::new(), + } + } + + fn recursive_build<'a, T, F>(&mut self, + offset: usize, + depth: usize, + objects: &mut [T], + info_getter: &F) + -> (usize, (usize, usize)) + where F: 'a + Fn(&T) -> (&'a [BBox], f32) + { + let me_index = self.nodes.len(); + + if objects.len() == 0 { + return (0, (0, 0)); + } else if objects.len() == 1 { + // Leaf node + let bi = self.bounds.len(); + let (obj_bounds, energy) = info_getter(&objects[0]); + self.bounds.extend(obj_bounds); + self.nodes.push(Node { + is_leaf: true, + bounds_range: (bi, self.bounds.len()), + energy: energy, + child_index: offset, + }); + + if self.depth < depth { + self.depth = depth; + } + + return (me_index, (bi, self.bounds.len())); + } else { + // Not a leaf node + self.nodes.push(Node { + is_leaf: false, + bounds_range: (0, 0), + energy: 0.0, + child_index: 0, + }); + + // Partition objects. + let (split_index, _) = sah_split(objects, &|obj_ref| info_getter(obj_ref).0); + + // Create child nodes + let (_, c1_bounds) = + self.recursive_build(offset, depth + 1, &mut objects[..split_index], info_getter); + let (c2_index, c2_bounds) = self.recursive_build(offset + split_index, + depth + 1, + &mut objects[split_index..], + info_getter); + + // Determine bounds + // TODO: do merging without the temporary vec. + let bi = self.bounds.len(); + let mut merged = Vec::new(); + merge_slices_append(&self.bounds[c1_bounds.0..c1_bounds.1], + &self.bounds[c2_bounds.0..c2_bounds.1], + &mut merged, + |b1, b2| *b1 | *b2); + self.bounds.extend(merged.drain(0..)); + + // Set node + let energy = self.nodes[me_index + 1].energy + self.nodes[c2_index].energy; + self.nodes[me_index] = Node { + is_leaf: false, + bounds_range: (bi, self.bounds.len()), + energy: energy, + child_index: c2_index, + }; + + return (me_index, (bi, self.bounds.len())); + } + } +} diff --git a/src/scene/assembly.rs b/src/scene/assembly.rs index 643f419..1883640 100644 --- a/src/scene/assembly.rs +++ b/src/scene/assembly.rs @@ -14,7 +14,7 @@ use surface::{Surface, SurfaceIntersection}; use transform_stack::TransformStack; -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub struct Assembly<'a> { // Instance list pub instances: &'a [Instance], @@ -22,16 +22,16 @@ pub struct Assembly<'a> { pub xforms: &'a [Matrix4x4], // Object list - pub objects: Vec>, + pub objects: &'a [Object<'a>], // Assembly list - pub assemblies: Vec>, + pub assemblies: &'a [Assembly<'a>], // Object accel pub object_accel: BVH<'a>, // Light accel - pub light_accel: LightTree, + pub light_accel: LightTree<'a>, } impl<'a> Assembly<'a> { @@ -257,7 +257,7 @@ impl<'a> AssemblyBuilder<'a> { .collect(); // Build light accel - let light_accel = LightTree::from_objects(&mut light_instances[..], |inst| { + let light_accel = LightTree::from_objects(self.arena, &mut light_instances[..], |inst| { let bounds = &bbs[bis[inst.id]..bis[inst.id + 1]]; let energy = match inst.instance_type { InstanceType::Object => { @@ -279,8 +279,8 @@ impl<'a> AssemblyBuilder<'a> { instances: self.arena.copy_slice(&self.instances), light_instances: self.arena.copy_slice(&light_instances), xforms: self.arena.copy_slice(&self.xforms), - objects: self.objects, - assemblies: self.assemblies, + objects: self.arena.copy_slice(&self.objects), + assemblies: self.arena.copy_slice(&self.assemblies), object_accel: object_accel, light_accel: light_accel, } @@ -335,7 +335,7 @@ impl<'a> AssemblyBuilder<'a> { -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum Object<'a> { Surface(&'a Surface), Light(&'a LightSource),