First pass at bounding volume hierarchy
This commit is contained in:
parent
e411f4abb4
commit
7bd45c8ad2
|
|
@ -0,0 +1,97 @@
|
||||||
|
use super::{BoundingBox, Primitive};
|
||||||
|
|
||||||
|
use crate::util::morton::morton_order_value;
|
||||||
|
use crate::util::normalizer::Point3Normalizer;
|
||||||
|
use crate::Real;
|
||||||
|
|
||||||
|
use nalgebra::{convert, Point3};
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum BoundingVolumeHierarchy<T: Real> {
|
||||||
|
Node {
|
||||||
|
bounds: BoundingBox<T>,
|
||||||
|
left: Arc<BoundingVolumeHierarchy<T>>,
|
||||||
|
right: Arc<BoundingVolumeHierarchy<T>>,
|
||||||
|
},
|
||||||
|
Leaf {
|
||||||
|
bounds: BoundingBox<T>,
|
||||||
|
primitive: Arc<dyn Primitive<T>>,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn centre<T: Real>(bounds: &BoundingBox<T>) -> Point3<T> {
|
||||||
|
let two = convert(2.0);
|
||||||
|
Point3::new(
|
||||||
|
(bounds.bounds[0].get_min() + bounds.bounds[0].get_max()) / two,
|
||||||
|
(bounds.bounds[1].get_min() + bounds.bounds[1].get_max()) / two,
|
||||||
|
(bounds.bounds[2].get_min() + bounds.bounds[2].get_max()) / two,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Real> BoundingVolumeHierarchy<T> {
|
||||||
|
pub fn build<'a, I>(primitives: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = &'a Arc<dyn Primitive<T>>>,
|
||||||
|
{
|
||||||
|
Self::from_node_vec(
|
||||||
|
primitives
|
||||||
|
.into_iter()
|
||||||
|
.map(|primitive| (primitive.bounding_box(), Arc::clone(primitive)))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_node_vec(nodes: Vec<(BoundingBox<T>, Arc<dyn Primitive<T>>)>) -> Self {
|
||||||
|
let overall_bounds = nodes
|
||||||
|
.iter()
|
||||||
|
.fold(BoundingBox::empty(), |a, (b, _)| a.union(b));
|
||||||
|
let normalizer = Point3Normalizer::new(overall_bounds);
|
||||||
|
let mut nodes = nodes;
|
||||||
|
nodes.sort_by(|(a, _), (b, _)| {
|
||||||
|
morton_order_value(normalizer.normalize(centre(a)))
|
||||||
|
.cmp(&morton_order_value(normalizer.normalize(centre(b))))
|
||||||
|
});
|
||||||
|
Self::from_sorted_nodes(nodes.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_sorted_nodes(nodes: &[(BoundingBox<T>, Arc<dyn Primitive<T>>)]) -> Self {
|
||||||
|
if nodes.len() >= 2 {
|
||||||
|
let midpoint = nodes.len() / 2;
|
||||||
|
let left = Arc::new(Self::from_sorted_nodes(&nodes[..midpoint]));
|
||||||
|
let right = Arc::new(Self::from_sorted_nodes(&nodes[midpoint..]));
|
||||||
|
let bounds = left.get_bounds().union(&right.get_bounds());
|
||||||
|
BoundingVolumeHierarchy::Node {
|
||||||
|
bounds,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
}
|
||||||
|
} else if nodes.len() == 1 {
|
||||||
|
match nodes[0] {
|
||||||
|
(bounds, ref primitive) => BoundingVolumeHierarchy::Leaf {
|
||||||
|
bounds,
|
||||||
|
primitive: Arc::clone(primitive),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BoundingVolumeHierarchy::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bounds(&self) -> BoundingBox<T> {
|
||||||
|
match self {
|
||||||
|
BoundingVolumeHierarchy::Node {
|
||||||
|
bounds,
|
||||||
|
left: _,
|
||||||
|
right: _,
|
||||||
|
} => *bounds,
|
||||||
|
BoundingVolumeHierarchy::Leaf {
|
||||||
|
bounds,
|
||||||
|
primitive: _,
|
||||||
|
} => *bounds,
|
||||||
|
BoundingVolumeHierarchy::None => BoundingBox::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,8 @@ pub use triangle::Triangle;
|
||||||
pub mod axis_aligned_bounding_box;
|
pub mod axis_aligned_bounding_box;
|
||||||
pub use axis_aligned_bounding_box::BoundingBox;
|
pub use axis_aligned_bounding_box::BoundingBox;
|
||||||
|
|
||||||
|
pub mod bounding_volume_hierarchy;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Ray<T: Real> {
|
pub struct Ray<T: Real> {
|
||||||
pub origin: Point3<T>,
|
pub origin: Point3<T>,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue