Make BHV contain a BinaryTree instead of being one

This commit is contained in:
Matthew Gordon 2020-07-20 21:46:36 -04:00
parent 4933993187
commit c322981486
1 changed files with 32 additions and 21 deletions

View File

@ -11,6 +11,8 @@ use nalgebra::{convert, Point3};
use std::mem::swap; use std::mem::swap;
type Tree<T> = BinaryTree<BoundingBox<T>, Box<dyn Primitive<T>>>;
/// Stores a set of [Primitives](Primitive) and accelerates raycasting /// Stores a set of [Primitives](Primitive) and accelerates raycasting
/// ///
/// Organizes the primitives into a binary tree based on their bounds, allowing the /// Organizes the primitives into a binary tree based on their bounds, allowing the
@ -19,7 +21,9 @@ use std::mem::swap;
/// Each node knows the overall bounds of all it's children, which means that a ray that /// Each node knows the overall bounds of all it's children, which means that a ray that
/// doesn't intersect the [BoundingBox](BoundingBox) of the node doesn't intersect any of /// doesn't intersect the [BoundingBox](BoundingBox) of the node doesn't intersect any of
/// the primitives stored in it's children. /// the primitives stored in it's children.
pub type BoundingVolumeHierarchy<T: Real> = BinaryTree<BoundingBox<T>, Box<dyn Primitive<T>>>; pub struct BoundingVolumeHierarchy<T: Real> {
tree: Tree<T>,
}
fn centre<T: Real>(bounds: &BoundingBox<T>) -> Point3<T> { fn centre<T: Real>(bounds: &BoundingBox<T>) -> Point3<T> {
let two = convert(2.0); let two = convert(2.0);
@ -37,15 +41,16 @@ impl<T: Real> BoundingVolumeHierarchy<T> {
where where
I: IntoIterator<Item = Box<dyn Primitive<T>>>, I: IntoIterator<Item = Box<dyn Primitive<T>>>,
{ {
Self::from_node_vec( let tree = Self::from_node_vec(
primitives primitives
.into_iter() .into_iter()
.map(|primitive| PrimitiveInfo(primitive.bounding_box(), Some(primitive))) .map(|primitive| PrimitiveInfo(primitive.bounding_box(), Some(primitive)))
.collect(), .collect(),
) );
Self { tree }
} }
fn from_node_vec(nodes: Vec<PrimitiveInfo<T>>) -> Self { fn from_node_vec(nodes: Vec<PrimitiveInfo<T>>) -> Tree<T> {
let overall_bounds = nodes let overall_bounds = nodes
.iter() .iter()
.fold(BoundingBox::empty(), |a, PrimitiveInfo(b, _)| a.union(b)); .fold(BoundingBox::empty(), |a, PrimitiveInfo(b, _)| a.union(b));
@ -58,37 +63,37 @@ impl<T: Real> BoundingVolumeHierarchy<T> {
Self::from_sorted_nodes(nodes.as_mut_slice()) Self::from_sorted_nodes(nodes.as_mut_slice())
} }
fn from_sorted_nodes(nodes: &mut [PrimitiveInfo<T>]) -> Self { fn from_sorted_nodes(nodes: &mut [PrimitiveInfo<T>]) -> Tree<T> {
if nodes.len() >= 2 { if nodes.len() >= 2 {
let midpoint = nodes.len() / 2; let midpoint = nodes.len() / 2;
let left = Box::new(Self::from_sorted_nodes(&mut nodes[..midpoint])); let left = Box::new(Self::from_sorted_nodes(&mut nodes[..midpoint]));
let right = Box::new(Self::from_sorted_nodes(&mut nodes[midpoint..])); let right = Box::new(Self::from_sorted_nodes(&mut nodes[midpoint..]));
let bounds = left.get_bounds().union(&right.get_bounds()); let bounds = Self::get_bounds(&left).union(&Self::get_bounds(&right));
BoundingVolumeHierarchy::Branch { Tree::Branch {
value: bounds, value: bounds,
left, left,
right, right,
} }
} else if nodes.len() == 1 { } else if nodes.len() == 1 {
let PrimitiveInfo(bounds, ref mut primitive_src) = nodes[0]; let PrimitiveInfo(_, ref mut primitive_src) = nodes[0];
let mut primitive = None; let mut primitive = None;
swap(primitive_src, &mut primitive); swap(primitive_src, &mut primitive);
let primitive = primitive.unwrap(); let primitive = primitive.unwrap();
BoundingVolumeHierarchy::Leaf { value: primitive } Tree::Leaf { value: primitive }
} else { } else {
BoundingVolumeHierarchy::None Tree::None
} }
} }
pub fn get_bounds(&self) -> BoundingBox<T> { pub fn get_bounds(tree: &Tree<T>) -> BoundingBox<T> {
match self { match tree {
BoundingVolumeHierarchy::Branch { Tree::Branch {
value, value,
left: _, left: _,
right: _, right: _,
} => *value, } => *value,
BoundingVolumeHierarchy::Leaf { value } => value.bounding_box(), Tree::Leaf { value } => value.bounding_box(),
BoundingVolumeHierarchy::None => BoundingBox::empty(), Tree::None => BoundingBox::empty(),
} }
} }
} }
@ -111,10 +116,10 @@ fn closest_intersection<T: Real>(
} }
} }
impl<T: Real> Intersect<T> for BoundingVolumeHierarchy<T> { impl<T: Real> Intersect<T> for Tree<T> {
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> { fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
match self { match self {
Self::Branch { Tree::Branch {
value: bounds, value: bounds,
left, left,
right, right,
@ -125,15 +130,21 @@ impl<T: Real> Intersect<T> for BoundingVolumeHierarchy<T> {
None None
} }
} }
Self::Leaf { value: primitive } => primitive.intersect(ray), Tree::Leaf { value: primitive } => primitive.intersect(ray),
Self::None => None, Tree::None => None,
} }
} }
} }
impl<T: Real> Intersect<T> for BoundingVolumeHierarchy<T> {
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
self.tree.intersect(ray)
}
}
impl<T: Real> HasBoundingBox<T> for BoundingVolumeHierarchy<T> { impl<T: Real> HasBoundingBox<T> for BoundingVolumeHierarchy<T> {
fn bounding_box(&self) -> BoundingBox<T> { fn bounding_box(&self) -> BoundingBox<T> {
self.get_bounds() Self::get_bounds(&self.tree)
} }
} }
@ -174,6 +185,6 @@ mod test {
fn contains_expected_number_of_primitives(spheres: Vec<Sphere<f32>>) -> bool { fn contains_expected_number_of_primitives(spheres: Vec<Sphere<f32>>) -> bool {
let target = BoundingVolumeHierarchy::build(sphere_vec_to_primitive_box_vec(&spheres)); let target = BoundingVolumeHierarchy::build(sphere_vec_to_primitive_box_vec(&spheres));
target.count_leaves() == spheres.len() target.tree.count_leaves() == spheres.len()
} }
} }