beevee: bvh: use Accelerated trait for objects
This will allow for the use of meshes inside the BVH. Returning the reference to a triangle inside the mesh directly instead of returning the reference to the mesh itself allows for more optimum execution.
This commit is contained in:
parent
5c0fc9689e
commit
3039607e4f
37
beevee/src/bvh/accelerated.rs
Normal file
37
beevee/src/bvh/accelerated.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use super::Intersected;
|
||||||
|
use crate::aabb::Bounded;
|
||||||
|
use crate::ray::Ray;
|
||||||
|
|
||||||
|
/// The trait for any mesh-like object to be used in the [`BVH`]. If your object is not an
|
||||||
|
/// aggregate, you should instead implement [`Intersected`] which derives this trait automatically.
|
||||||
|
///
|
||||||
|
/// This trait is there to accomodate for aggregate objects inside the [`BVH`]: you can implement a
|
||||||
|
/// faster look-up of information using a [`BVH`] in a mesh for example, returning directly the
|
||||||
|
/// reference to a hit triangle. This enables us to return this triangle instead of returning a
|
||||||
|
/// reference to the whole mesh.
|
||||||
|
///
|
||||||
|
/// [`BVH`]: struct.BVH.html
|
||||||
|
/// [`Intersected`]: struct.Intersected.html
|
||||||
|
pub trait Accelerated: Bounded {
|
||||||
|
/// The type contained in your [`Accelerated`] structure
|
||||||
|
///
|
||||||
|
/// [`Accelerated`]: struct.Accelerated.html
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
/// Return None if no intersection happens with the ray, or a tuple of distance along the ray
|
||||||
|
/// and a reference to the object that was hit.
|
||||||
|
fn intersect(&self, ray: &Ray) -> Option<(f32, &Self::Output)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The automatic implementation for any [`Intersected`] object to be used in the [`BVH`].
|
||||||
|
impl<T> Accelerated for T
|
||||||
|
where
|
||||||
|
T: Intersected,
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
/// Return a reference to `self` when a distance was found.
|
||||||
|
fn intersect(&self, ray: &Ray) -> Option<(f32, &Self::Output)> {
|
||||||
|
self.intersect(ray).map(|t| (t, self))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
use crate::aabb::Bounded;
|
use crate::aabb::Bounded;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
|
|
||||||
/// The trait for any object to be used in the [`BVH`].
|
/// The trait for any object to be used in the [`BVH`]. Its derivation for [`Accelerated`] is
|
||||||
|
/// automatically derived to return a reference to itself. If this not the intended semantics, see
|
||||||
|
/// [`Accelerated`].
|
||||||
///
|
///
|
||||||
|
/// [`Accelerated`]: struct.Accelerated.html
|
||||||
/// [`BVH`]: struct.BVH.html
|
/// [`BVH`]: struct.BVH.html
|
||||||
pub trait Intersected: Bounded {
|
pub trait Intersected: Bounded {
|
||||||
/// Return None if there is no intersection, or the distance along the ray to the closest
|
/// Return None if there is no intersection, or the distance along the ray to the closest
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
//! The Boudning Volume Hiearchy
|
//! The Boudning Volume Hiearchy
|
||||||
|
|
||||||
|
mod accelerated;
|
||||||
|
pub use accelerated::*;
|
||||||
|
|
||||||
mod intersected;
|
mod intersected;
|
||||||
pub use intersected::*;
|
pub use intersected::*;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::Intersected;
|
use super::Accelerated;
|
||||||
use crate::aabb::AABB;
|
use crate::aabb::AABB;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::Axis;
|
use crate::Axis;
|
||||||
|
@ -23,9 +23,9 @@ struct Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The BVH containing all the objects of type O.
|
/// The BVH containing all the objects of type O.
|
||||||
/// This type must implement [`Intersected`].
|
/// This type must implement [`Accelerated`].
|
||||||
///
|
///
|
||||||
/// [`Intersected`]: trait.Intersected.html
|
/// [`Accelerated`]: trait.Accelerated.html
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct BVH {
|
pub struct BVH {
|
||||||
tree: Node,
|
tree: Node,
|
||||||
|
@ -92,7 +92,7 @@ impl BVH {
|
||||||
/// let spheres: &mut [Sphere] = &mut [Sphere{ center: Point::origin(), radius: 2.5 }];
|
/// let spheres: &mut [Sphere] = &mut [Sphere{ center: Point::origin(), radius: 2.5 }];
|
||||||
/// let bvh = BVH::build(spheres);
|
/// let bvh = BVH::build(spheres);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn build<O: Intersected>(objects: &mut [O]) -> Self {
|
pub fn build<O: Accelerated>(objects: &mut [O]) -> Self {
|
||||||
Self::with_max_capacity(objects, 32)
|
Self::with_max_capacity(objects, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ impl BVH {
|
||||||
/// let spheres: &mut [Sphere] = &mut [Sphere{ center: Point::origin(), radius: 2.5 }];
|
/// let spheres: &mut [Sphere] = &mut [Sphere{ center: Point::origin(), radius: 2.5 }];
|
||||||
/// let bvh = BVH::with_max_capacity(spheres, 32);
|
/// let bvh = BVH::with_max_capacity(spheres, 32);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with_max_capacity<O: Intersected>(objects: &mut [O], max_cap: usize) -> Self {
|
pub fn with_max_capacity<O: Accelerated>(objects: &mut [O], max_cap: usize) -> Self {
|
||||||
let tree = build_node(objects, 0, objects.len(), max_cap);
|
let tree = build_node(objects, 0, objects.len(), max_cap);
|
||||||
Self { tree }
|
Self { tree }
|
||||||
}
|
}
|
||||||
|
@ -226,8 +226,8 @@ impl BVH {
|
||||||
/// let bvh = BVH::with_max_capacity(spheres, 32);
|
/// let bvh = BVH::with_max_capacity(spheres, 32);
|
||||||
/// assert!(bvh.is_sound(spheres));
|
/// assert!(bvh.is_sound(spheres));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn is_sound<O: Intersected>(&self, objects: &[O]) -> bool {
|
pub fn is_sound<O: Accelerated>(&self, objects: &[O]) -> bool {
|
||||||
fn check_node<O: Intersected>(objects: &[O], node: &Node) -> bool {
|
fn check_node<O: Accelerated>(objects: &[O], node: &Node) -> bool {
|
||||||
if node.begin > node.end {
|
if node.begin > node.end {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -322,17 +322,21 @@ impl BVH {
|
||||||
/// assert_eq!(dist, 0.5);
|
/// assert_eq!(dist, 0.5);
|
||||||
/// assert_eq!(obj, &spheres[0]);
|
/// assert_eq!(obj, &spheres[0]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn walk<'o, O: Intersected>(&self, ray: &Ray, objects: &'o [O]) -> Option<(f32, &'o O)> {
|
pub fn walk<'o, O: Accelerated>(
|
||||||
|
&self,
|
||||||
|
ray: &Ray,
|
||||||
|
objects: &'o [O],
|
||||||
|
) -> Option<(f32, &'o O::Output)> {
|
||||||
walk_rec_helper(ray, objects, &self.tree, std::f32::INFINITY)
|
walk_rec_helper(ray, objects, &self.tree, std::f32::INFINITY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_rec_helper<'o, O: Intersected>(
|
fn walk_rec_helper<'o, O: Accelerated>(
|
||||||
ray: &Ray,
|
ray: &Ray,
|
||||||
objects: &'o [O],
|
objects: &'o [O],
|
||||||
node: &Node,
|
node: &Node,
|
||||||
min: f32,
|
min: f32,
|
||||||
) -> Option<(f32, &'o O)> {
|
) -> Option<(f32, &'o O::Output)> {
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
|
@ -340,7 +344,7 @@ fn walk_rec_helper<'o, O: Intersected>(
|
||||||
NodeEnum::Leaf => objects[node.begin..node.end]
|
NodeEnum::Leaf => objects[node.begin..node.end]
|
||||||
.iter()
|
.iter()
|
||||||
// This turns the Option<f32> of an intersection into an Option<(f32, &O)>
|
// This turns the Option<f32> of an intersection into an Option<(f32, &O)>
|
||||||
.filter_map(|o| o.intersect(ray).map(|d| (d, o)))
|
.filter_map(|o| o.intersect(ray))
|
||||||
// Discard values that are too far away
|
// Discard values that are too far away
|
||||||
.filter(|(dist, _)| dist < &min)
|
.filter(|(dist, _)| dist < &min)
|
||||||
// Only keep the minimum value, if there is one
|
// Only keep the minimum value, if there is one
|
||||||
|
@ -382,14 +386,14 @@ fn walk_rec_helper<'o, O: Intersected>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounds_from_slice<O: Intersected>(objects: &[O]) -> AABB {
|
fn bounds_from_slice<O: Accelerated>(objects: &[O]) -> AABB {
|
||||||
objects
|
objects
|
||||||
.iter()
|
.iter()
|
||||||
.map(|o| o.aabb())
|
.map(|o| o.aabb())
|
||||||
.fold(AABB::empty(), |acc, other| acc.union(&other))
|
.fold(AABB::empty(), |acc, other| acc.union(&other))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_node<O: Intersected>(objects: &mut [O], begin: usize, end: usize, max_cap: usize) -> Node {
|
fn build_node<O: Accelerated>(objects: &mut [O], begin: usize, end: usize, max_cap: usize) -> Node {
|
||||||
let aabb = bounds_from_slice(objects);
|
let aabb = bounds_from_slice(objects);
|
||||||
// Don't split nodes under capacity
|
// Don't split nodes under capacity
|
||||||
if objects.len() <= max_cap {
|
if objects.len() <= max_cap {
|
||||||
|
@ -437,7 +441,7 @@ fn build_node<O: Intersected>(objects: &mut [O], begin: usize, end: usize, max_c
|
||||||
|
|
||||||
/// Returns the index at which to split for SAH, the Axis along which to split, and the calculated
|
/// Returns the index at which to split for SAH, the Axis along which to split, and the calculated
|
||||||
/// cost.
|
/// cost.
|
||||||
fn compute_sah<O: Intersected>(
|
fn compute_sah<O: Accelerated>(
|
||||||
objects: &mut [O],
|
objects: &mut [O],
|
||||||
surface: f32,
|
surface: f32,
|
||||||
max_cap: usize,
|
max_cap: usize,
|
||||||
|
|
Loading…
Reference in a new issue