During BVH construction, merge BBox time samples based on a threshold.
If the average surface area of all the time samples is close enough to the surface area of their union, just take the union and use that. This both makes the BVH smaller in memory (time samples don't propigate up the tree beyond their usefulness) and makes it faster since traversal can avoid interpolating BBoxes when there's only one BBox for a node.
This commit is contained in:
parent
55c64a3392
commit
c92a8c4da0
|
@ -128,9 +128,11 @@ impl<'a> BVH<'a> {
|
|||
-> &'a mut BVHNode<'a> {
|
||||
match &base.nodes[node_index] {
|
||||
&BVHBaseNode::Internal { bounds_range, children_indices, split_axis } => {
|
||||
let mut node = unsafe { arena.alloc_uninitialized::<BVHNode>() };
|
||||
let mut node = unsafe { arena.alloc_uninitialized_with_alignment::<BVHNode>(32) };
|
||||
|
||||
let bounds = arena.copy_slice(&base.bounds[bounds_range.0..bounds_range.1]);
|
||||
let bounds =
|
||||
arena.copy_slice_with_alignment(&base.bounds[bounds_range.0..bounds_range.1],
|
||||
32);
|
||||
let child1 = BVH::construct_from_base(arena, base, children_indices.0);
|
||||
let child2 = BVH::construct_from_base(arena, base, children_indices.1);
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ use super::objects_split::{sah_split, median_split};
|
|||
|
||||
pub const BVH_MAX_DEPTH: usize = 42;
|
||||
|
||||
// Amount bigger the union of all time samples can be
|
||||
// and still use the union rather than preserve the
|
||||
// individual time samples.
|
||||
const USE_UNION_FACTOR: f32 = 1.4;
|
||||
|
||||
/// An intermediary structure for creating a BVH.
|
||||
#[derive(Debug)]
|
||||
pub struct BVHBase {
|
||||
|
@ -104,11 +109,24 @@ impl BVHBase {
|
|||
return (0, (0, 0));
|
||||
} else if objects.len() <= objects_per_leaf {
|
||||
// Leaf node
|
||||
self.acc_bounds(objects, bounder);
|
||||
let bi = self.bounds.len();
|
||||
for b in self.bounds_cache.iter() {
|
||||
self.bounds.push(*b);
|
||||
// Get bounds
|
||||
{
|
||||
// We make sure that it's worth having multiple time samples, and if not
|
||||
// we reduce to the union of the time samples.
|
||||
self.acc_bounds(objects, bounder);
|
||||
let union_bounds = self.bounds_cache.iter().fold(BBox::new(), |b1, b2| (b1 | *b2));
|
||||
let average_area =
|
||||
self.bounds_cache.iter().fold(0.0, |area, bb| area + bb.surface_area()) /
|
||||
self.bounds_cache.len() as f32;
|
||||
if union_bounds.surface_area() <= (average_area * USE_UNION_FACTOR) {
|
||||
self.bounds.push(union_bounds);
|
||||
} else {
|
||||
self.bounds.extend(&self.bounds_cache);
|
||||
}
|
||||
}
|
||||
|
||||
// Create node
|
||||
self.nodes.push(BVHBaseNode::Leaf {
|
||||
bounds_range: (bi, self.bounds.len()),
|
||||
object_range: (offset, offset + objects.len()),
|
||||
|
@ -155,12 +173,24 @@ impl BVHBase {
|
|||
// 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..));
|
||||
{
|
||||
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);
|
||||
// We make sure that it's worth having multiple time samples, and if not
|
||||
// we reduce to the union of the time samples.
|
||||
let union_bounds = merged.iter().fold(BBox::new(), |b1, b2| (b1 | *b2));
|
||||
let average_area = merged.iter().fold(0.0, |area, bb| area + bb.surface_area()) /
|
||||
merged.len() as f32;
|
||||
if union_bounds.surface_area() <= (average_area * USE_UNION_FACTOR) {
|
||||
self.bounds.push(union_bounds);
|
||||
} else {
|
||||
self.bounds.extend(merged.drain(0..));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set node
|
||||
self.nodes[me] = BVHBaseNode::Internal {
|
||||
|
|
|
@ -80,11 +80,8 @@ impl BBox {
|
|||
}
|
||||
|
||||
pub fn surface_area(&self) -> f32 {
|
||||
let x = self.max.x() - self.min.x();
|
||||
let y = self.max.y() - self.min.y();
|
||||
let z = self.max.z() - self.min.z();
|
||||
|
||||
((x * y) + (y * z) + (z * x)) * 2.0
|
||||
let d = self.max - self.min;
|
||||
((d.x() * d.y()) + (d.y() * d.z()) + (d.z() * d.x())) * 2.0
|
||||
}
|
||||
|
||||
pub fn center(&self) -> Point {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||
use mem_arena::MemArena;
|
||||
|
||||
use accel::{LightAccel, LightTree};
|
||||
use accel::BVH4;
|
||||
use accel::BVH;
|
||||
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: BVH4<'a>,
|
||||
pub object_accel: BVH<'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 = BVH4::from_objects(self.arena,
|
||||
&mut self.instances[..],
|
||||
1,
|
||||
|inst| &bbs[bis[inst.id]..bis[inst.id + 1]]);
|
||||
let object_accel = BVH::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 BVH4.
|
||||
/// This is used for building the assembly's BVH.
|
||||
fn instance_bounds(&self) -> (Vec<usize>, Vec<BBox>) {
|
||||
let mut indices = vec![0];
|
||||
let mut bounds = Vec::new();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use mem_arena::MemArena;
|
||||
|
||||
use accel::BVH4;
|
||||
use accel::BVH;
|
||||
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: BVH4<'a>,
|
||||
accel: BVH<'a>,
|
||||
}
|
||||
|
||||
impl<'a> TriangleMesh<'a> {
|
||||
|
@ -44,10 +44,10 @@ impl<'a> TriangleMesh<'a> {
|
|||
bounds
|
||||
};
|
||||
|
||||
let accel = BVH4::from_objects(arena,
|
||||
&mut indices[..],
|
||||
3,
|
||||
|tri_i| &bounds[*tri_i..(*tri_i + time_samples)]);
|
||||
let accel = BVH::from_objects(arena,
|
||||
&mut indices[..],
|
||||
3,
|
||||
|tri_i| &bounds[*tri_i..(*tri_i + time_samples)]);
|
||||
|
||||
TriangleMesh {
|
||||
time_samples: time_samples,
|
||||
|
|
Loading…
Reference in New Issue
Block a user