Big rijiggering of types

This commit is contained in:
Matthew Gordon 2020-06-11 22:13:51 -04:00
parent 01259e1e55
commit 90bb7d84af
10 changed files with 203 additions and 188 deletions

View File

@ -1,14 +1,14 @@
use criterion::{criterion_group, criterion_main, Criterion};
use vanrijn::partial_render_scene;
use vanrijn::colour::{ColourRgbF, NamedColour};
use vanrijn::materials::{LambertianMaterial, PhongMaterial, ReflectiveMaterial};
use vanrijn::materials::ReflectiveMaterial;
use vanrijn::mesh::load_obj;
use vanrijn::raycasting::{BoundingVolumeHierarchy, Plane, Primitive, Sphere};
use vanrijn::partial_render_scene;
use vanrijn::raycasting::BoundingVolumeHierarchy;
use vanrijn::scene::Scene;
use vanrijn::util::Tile;
use nalgebra::{Point3, Vector3};
use nalgebra::Point3;
use std::path::Path;
use std::sync::Arc;
@ -22,55 +22,17 @@ fn simple_scene(bencher: &mut Criterion) {
let scene = Scene {
camera_location: Point3::new(-2.0, 1.0, -5.0),
objects: vec![
Box::new(Plane::new(
Vector3::new(0.0, 1.0, 0.0),
-2.0,
Arc::new(LambertianMaterial {
colour: ColourRgbF::new(0.55, 0.27, 0.04),
diffuse_strength: 0.1,
}),
)) as Box<dyn Primitive<f64>>,
Box::new(Sphere::new(
Point3::new(-6.25, -0.5, 1.0),
1.0,
Arc::new(LambertianMaterial {
colour: ColourRgbF::from_named(NamedColour::Green),
diffuse_strength: 0.1,
}),
)),
Box::new(Sphere::new(
Point3::new(-4.25, -0.5, 2.0),
1.0,
objects: vec![Box::new(BoundingVolumeHierarchy::build(
load_obj(
&model_file_path,
Arc::new(ReflectiveMaterial {
colour: ColourRgbF::from_named(NamedColour::Blue),
diffuse_strength: 0.01,
reflection_strength: 0.99,
}),
)),
Box::new(Sphere::new(
Point3::new(-5.0, 1.5, 1.0),
1.0,
Arc::new(PhongMaterial {
colour: ColourRgbF::from_named(NamedColour::Red),
colour: ColourRgbF::from_named(NamedColour::Yellow),
diffuse_strength: 0.05,
smoothness: 100.0,
specular_strength: 1.0,
reflection_strength: 0.9,
}),
)),
Box::new(BoundingVolumeHierarchy::build(
&load_obj(
&model_file_path,
Arc::new(PhongMaterial {
colour: ColourRgbF::from_named(NamedColour::Yellow),
diffuse_strength: 0.05,
smoothness: 100.0,
specular_strength: 1.0,
}),
)
.unwrap(),
)),
],
)
.unwrap(),
))],
};
bencher.bench_function("simple_scene", |b| {

View File

@ -13,12 +13,14 @@ use nalgebra::{Point3, Vector3};
use std::path::Path;
use std::sync::{mpsc, Arc};
use vanrijn::partial_render_scene;
use vanrijn::colour::{ColourRgbF, NamedColour};
use vanrijn::image::{ClampingToneMapper, ImageRgbU8, ToneMapper};
use vanrijn::materials::{LambertianMaterial, PhongMaterial, ReflectiveMaterial};
use vanrijn::mesh::load_obj;
use vanrijn::raycasting::{BoundingVolumeHierarchy, Plane, Primitive, Sphere};
use vanrijn::partial_render_scene;
use vanrijn::raycasting::{
Aggregate, BoundingVolumeHierarchy, Plane, Primitive, Sphere,
};
use vanrijn::scene::Scene;
use vanrijn::util::{Tile, TileIterator};
@ -72,55 +74,56 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Loading object...");
let model_object = load_obj(
&model_file_path,
Arc::new(PhongMaterial {
colour: ColourRgbF::from_named(NamedColour::Blue),
diffuse_strength: 0.05,
smoothness: 100.0,
specular_strength: 1.0,
Arc::new(ReflectiveMaterial {
colour: ColourRgbF::from_named(NamedColour::Yellow),
diffuse_strength: 0.01,
reflection_strength: 0.9,
}),
)?;
println!("Building BVH...");
let model_bvh = Box::new(BoundingVolumeHierarchy::build(&model_object));
let model_bvh: Box<dyn Aggregate<_>> = Box::new(BoundingVolumeHierarchy::build(model_object));
println!("Constructing Scene...");
let scene = Scene {
camera_location: Point3::new(-2.0, 1.0, -5.0),
objects: vec![
Box::new(Plane::new(
Vector3::new(0.0, 1.0, 0.0),
-2.0,
Arc::new(LambertianMaterial {
colour: ColourRgbF::new(0.55, 0.27, 0.04),
diffuse_strength: 0.1,
}),
)) as Box<dyn Primitive<f64>>,
Box::new(Sphere::new(
Point3::new(-6.25, -0.5, 1.0),
1.0,
Arc::new(LambertianMaterial {
colour: ColourRgbF::from_named(NamedColour::Green),
diffuse_strength: 0.1,
}),
)),
Box::new(Sphere::new(
Point3::new(-4.25, -0.5, 2.0),
1.0,
Arc::new(ReflectiveMaterial {
colour: ColourRgbF::from_named(NamedColour::Blue),
diffuse_strength: 0.01,
reflection_strength: 0.99,
}),
)),
Box::new(Sphere::new(
Point3::new(-5.0, 1.5, 1.0),
1.0,
Arc::new(PhongMaterial {
colour: ColourRgbF::from_named(NamedColour::Red),
diffuse_strength: 0.05,
smoothness: 100.0,
specular_strength: 1.0,
}),
)),
Box::new(vec![
Box::new(Plane::new(
Vector3::new(0.0, 1.0, 0.0),
-2.0,
Arc::new(LambertianMaterial {
colour: ColourRgbF::new(0.55, 0.27, 0.04),
diffuse_strength: 0.1,
}),
)) as Box<dyn Primitive<f64>>,
Box::new(Sphere::new(
Point3::new(-6.25, -0.5, 1.0),
1.0,
Arc::new(LambertianMaterial {
colour: ColourRgbF::from_named(NamedColour::Green),
diffuse_strength: 0.1,
}),
)),
Box::new(Sphere::new(
Point3::new(-4.25, -0.5, 2.0),
1.0,
Arc::new(ReflectiveMaterial {
colour: ColourRgbF::from_named(NamedColour::Blue),
diffuse_strength: 0.01,
reflection_strength: 0.99,
}),
)),
Box::new(Sphere::new(
Point3::new(-5.0, 1.5, 1.0),
1.0,
Arc::new(PhongMaterial {
colour: ColourRgbF::from_named(NamedColour::Red),
diffuse_strength: 0.05,
smoothness: 100.0,
specular_strength: 1.0,
}),
)),
]) as Box<dyn Aggregate<f64>>,
model_bvh,
],
};

View File

@ -68,7 +68,7 @@ mod wavefront_obj {
pub fn load_obj<T: Real>(
filename: &Path,
material: Arc<dyn Material<T>>,
) -> Result<Vec<Arc<dyn Primitive<T>>>>
) -> Result<Vec<Box<dyn Primitive<T>>>>
where
T: SupersetOf<f32>,
{
@ -80,7 +80,7 @@ mod wavefront_obj {
.flat_map(|object| object.groups.iter())
.flat_map(|group| group.polys.iter())
.flat_map(|poly| get_triangles(poly, &obj.position, &obj.normal, material.clone()))
.map(|triangle| Arc::new(triangle) as Arc<dyn Primitive<T>>)
.map(|triangle| Box::new(triangle) as Box<dyn Primitive<T>>)
.collect())
}
}

View File

@ -1,4 +1,6 @@
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectP, IntersectionInfo, Primitive, Ray};
use super::{
Aggregate, BoundingBox, HasBoundingBox, Intersect, IntersectP, IntersectionInfo, Primitive, Ray,
};
use crate::util::morton::morton_order_value_3d;
use crate::util::normalizer::Point3Normalizer;
@ -6,7 +8,7 @@ use crate::Real;
use nalgebra::{convert, Point3};
use std::sync::Arc;
use std::mem::swap;
/// Stores a set of [Primitives](Primitive) and accelerates raycasting
///
@ -16,7 +18,6 @@ use std::sync::Arc;
/// 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
/// the primitives stored in it's children.
#[derive(Clone)]
pub enum BoundingVolumeHierarchy<T: Real> {
Node {
bounds: BoundingBox<T>,
@ -25,7 +26,7 @@ pub enum BoundingVolumeHierarchy<T: Real> {
},
Leaf {
bounds: BoundingBox<T>,
primitive: Arc<dyn Primitive<T>>,
primitive: Box<dyn Primitive<T>>,
},
None,
}
@ -39,17 +40,17 @@ fn centre<T: Real>(bounds: &BoundingBox<T>) -> Point3<T> {
)
}
struct PrimitiveInfo<T: Real>(BoundingBox<T>, Arc<dyn Primitive<T>>);
struct PrimitiveInfo<T: Real>(BoundingBox<T>, Option<Box<dyn Primitive<T>>>);
impl<T: Real> BoundingVolumeHierarchy<T> {
pub fn build<'a, I>(primitives: I) -> Self
where
I: IntoIterator<Item = &'a Arc<dyn Primitive<T>>>,
I: IntoIterator<Item = Box<dyn Primitive<T>>>,
{
Self::from_node_vec(
primitives
.into_iter()
.map(|primitive| PrimitiveInfo(primitive.bounding_box(), Arc::clone(primitive)))
.map(|primitive| PrimitiveInfo(primitive.bounding_box(), Some(primitive)))
.collect(),
)
}
@ -64,14 +65,14 @@ impl<T: Real> BoundingVolumeHierarchy<T> {
morton_order_value_3d(normalizer.normalize(centre(a)))
.cmp(&morton_order_value_3d(normalizer.normalize(centre(b))))
});
Self::from_sorted_nodes(nodes.as_slice())
Self::from_sorted_nodes(nodes.as_mut_slice())
}
fn from_sorted_nodes(nodes: &[PrimitiveInfo<T>]) -> Self {
fn from_sorted_nodes(nodes: &mut [PrimitiveInfo<T>]) -> Self {
if nodes.len() >= 2 {
let midpoint = nodes.len() / 2;
let left = Box::new(Self::from_sorted_nodes(&nodes[..midpoint]));
let right = Box::new(Self::from_sorted_nodes(&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 bounds = left.get_bounds().union(&right.get_bounds());
BoundingVolumeHierarchy::Node {
bounds,
@ -79,11 +80,11 @@ impl<T: Real> BoundingVolumeHierarchy<T> {
right,
}
} else if nodes.len() == 1 {
let PrimitiveInfo(bounds, ref primitive) = nodes[0];
BoundingVolumeHierarchy::Leaf {
bounds,
primitive: Arc::clone(primitive),
}
let PrimitiveInfo(bounds, ref mut primitive_src) = nodes[0];
let mut primitive = None;
swap(primitive_src, &mut primitive);
let primitive = primitive.unwrap();
BoundingVolumeHierarchy::Leaf { bounds, primitive }
} else {
BoundingVolumeHierarchy::None
}
@ -167,7 +168,7 @@ impl<T: Real> HasBoundingBox<T> for BoundingVolumeHierarchy<T> {
}
}
impl<T: Real> Primitive<T> for BoundingVolumeHierarchy<T> {}
impl<T: Real> Aggregate<T> for BoundingVolumeHierarchy<T> {}
pub struct FilterIterator<'a, T: Real> {
unsearched_subtrees: Vec<&'a BoundingVolumeHierarchy<T>>,
@ -186,8 +187,8 @@ impl<'a, T: Real> FilterIterator<'a, T> {
}
}
impl<T: Real> Iterator for FilterIterator<'_, T> {
type Item = Arc<dyn Primitive<T>>;
impl<'a, T: Real> Iterator for FilterIterator<'a, T> {
type Item = &'a dyn Primitive<T>;
fn next(&mut self) -> Option<Self::Item> {
//let mut result = Option::None;
@ -203,9 +204,12 @@ impl<T: Real> Iterator for FilterIterator<'_, T> {
self.unsearched_subtrees.push(left);
}
}
BoundingVolumeHierarchy::Leaf { bounds, primitive } => {
BoundingVolumeHierarchy::Leaf {
bounds,
ref primitive,
} => {
if (self.predicate)(bounds) {
return Some(Arc::clone(primitive));
return Some(&**primitive);
}
}
BoundingVolumeHierarchy::None => {}
@ -226,6 +230,8 @@ mod test {
use crate::raycasting::Sphere;
use nalgebra::Point3;
use std::sync::Arc;
impl<T: Arbitrary + Real> Arbitrary for Sphere<T> {
fn arbitrary<G: Gen>(g: &mut G) -> Sphere<T> {
let centre = <Point3<T> as Arbitrary>::arbitrary(g);
@ -234,42 +240,20 @@ mod test {
}
}
fn sphere_vec_to_primitive_arc_vec<T: Real>(
fn sphere_vec_to_primitive_box_vec<T: Real>(
spheres: &Vec<Sphere<T>>,
) -> Vec<Arc<dyn Primitive<T>>> {
let mut prims: Vec<Arc<dyn Primitive<T>>> = Vec::with_capacity(spheres.len());
) -> Vec<Box<dyn Primitive<T>>> {
let mut prims: Vec<Box<dyn Primitive<T>>> = Vec::with_capacity(spheres.len());
for sphere in spheres {
prims.push(Arc::new(sphere.clone()));
prims.push(Box::new(sphere.clone()));
}
prims
}
#[quickcheck]
fn contains_expected_number_of_primitives(spheres: Vec<Sphere<f32>>) -> bool {
let target =
BoundingVolumeHierarchy::build(sphere_vec_to_primitive_arc_vec(&spheres).iter());
let target = BoundingVolumeHierarchy::build(sphere_vec_to_primitive_box_vec(&spheres));
target.count_leaves() == spheres.len()
}
#[quickcheck]
fn finds_expected_points(spheres: Vec<Sphere<f32>>, p: Point3<f32>) -> bool {
let primitives = sphere_vec_to_primitive_arc_vec(&spheres);
let target = BoundingVolumeHierarchy::build(primitives.iter());
let expected_hits: Vec<Arc<dyn Primitive<f32>>> = primitives
.iter()
.filter(|elem| elem.bounding_box().contains_point(p))
.cloned()
.collect();
let found_hits: Vec<Arc<dyn Primitive<f32>>> = FilterIterator::new(
&target,
Box::new(move |elem: &BoundingBox<f32>| elem.contains_point(p)),
)
.collect();
expected_hits.iter().all(|expected_hit| {
found_hits
.iter()
.any(|found_hit| Arc::ptr_eq(found_hit, expected_hit))
})
}
}

View File

@ -20,6 +20,8 @@ pub use axis_aligned_bounding_box::BoundingBox;
pub mod bounding_volume_hierarchy;
pub use bounding_volume_hierarchy::BoundingVolumeHierarchy;
pub mod vec_aggregate;
/// A ray, consisting or a start point and direction
///
/// This is the basic ray struct used to define things like a line-of-sight
@ -123,13 +125,19 @@ pub trait HasBoundingBox<T: Real>: Send + Sync {
/// Any geometric object which can have an affine transformation applied to it
///
/// Used for moving, rotating or scaling primitives
pub trait Transform<T: Real>: Send + Sync {
pub trait Transform<T: Real> {
/// Create a new object by applying the transformation to this object.
fn transform(&mut self, transformation: &Affine3<T>) -> &Self;
fn transform(&self, transformation: &Affine3<T>) -> Self;
}
/// A basic geometric primitive such as a sphere or a triangle
pub trait Primitive<T: Real>: Intersect<T> + HasBoundingBox<T> {}
pub trait Primitive<T: Real>: Intersect<T> + HasBoundingBox<T> {
// / Create a new object by applying the transformation to this object.
//fn transform(&self, transformation: &Affine3<T>) -> dyn Primitive<T>;
}
/// Either a primitive or a collection of primitives
pub trait Aggregate<T: Real>: Intersect<T> + HasBoundingBox<T> {}
#[cfg(test)]
mod tests {

View File

@ -7,6 +7,7 @@ use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive,
use std::sync::Arc;
#[derive(Clone)]
pub struct Plane<T: Real> {
normal: Vector3<T>,
tangent: Vector3<T>,
@ -37,14 +38,16 @@ impl<T: Real> Plane<T> {
}
impl<T: Real> Transform<T> for Plane<T> {
fn transform(&mut self, transformation: &Affine3<T>) -> &Self {
self.normal = transformation.transform_vector(&self.normal).normalize();
self.cotangent = transformation.transform_vector(&self.cotangent).normalize();
self.cotangent = self.normal.cross(&self.cotangent);
self.distance_from_origin = transformation
.transform_vector(&(self.normal * self.distance_from_origin))
.norm();
self
fn transform(&self, transformation: &Affine3<T>) -> Self {
Plane {
normal: transformation.transform_vector(&self.normal).normalize(),
cotangent: transformation.transform_vector(&self.cotangent).normalize(),
tangent: self.normal.cross(&self.cotangent),
distance_from_origin: transformation
.transform_vector(&(self.normal * self.distance_from_origin))
.norm(),
material: Arc::clone(&self.material),
}
}
}

View File

@ -25,14 +25,16 @@ impl<T: Real> Sphere<T> {
}
impl<T: Real> Transform<T> for Sphere<T> {
fn transform(&mut self, transformation: &Affine3<T>) -> &Self {
self.centre = transformation.transform_point(&self.centre);
// This is not the most efficient way of calculating the radius,
//but will work as long as the resulting shape is still a sphere.
self.radius = transformation
.transform_vector(&Vector3::new(self.radius, T::zero(), T::zero()))
.norm();
self
fn transform(&self, transformation: &Affine3<T>) -> Self {
Sphere {
centre: transformation.transform_point(&self.centre),
// This is not the most efficient way of calculating the radius,
//but will work as long as the resulting shape is still a sphere.
radius: transformation
.transform_vector(&Vector3::new(self.radius, T::zero(), T::zero()))
.norm(),
material: Arc::clone(&self.material),
}
}
}
@ -207,7 +209,7 @@ mod tests {
if radius <= 0.0 {
return TestResult::discard();
};
let mut sphere = Sphere::new(
let sphere = Sphere::new(
sphere_centre,
radius,
Arc::new(LambertianMaterial::new_dummy()),
@ -215,7 +217,7 @@ mod tests {
let expected_centre = sphere.centre + translation_vector;
let mut transformation = Affine3::identity();
transformation *= Translation3::from(translation_vector);
sphere.transform(&transformation);
let sphere = sphere.transform(&transformation);
TestResult::from_bool(expected_centre == sphere.centre)
}
@ -228,7 +230,7 @@ mod tests {
if radius <= 0.0 {
return TestResult::discard();
};
let mut sphere = Sphere::new(
let sphere = Sphere::new(
sphere_centre,
radius,
Arc::new(LambertianMaterial::new_dummy()),
@ -236,7 +238,7 @@ mod tests {
let expected_radius = sphere.radius;
let mut transformation = Affine3::identity();
transformation *= Translation3::from(translation_vector);
sphere.transform(&transformation);
let sphere = sphere.transform(&transformation);
TestResult::from_bool(expected_radius == sphere.radius)
}
@ -249,7 +251,7 @@ mod tests {
if radius <= 0.0 {
return TestResult::discard();
};
let mut sphere = Sphere::new(
let sphere = Sphere::new(
sphere_centre,
radius,
Arc::new(LambertianMaterial::new_dummy()),
@ -259,7 +261,7 @@ mod tests {
transformation *= Translation3::from(sphere.centre.coords)
* Rotation3::new(rotation_vector)
* Translation3::from(-sphere.centre.coords);
sphere.transform(&transformation);
let sphere = sphere.transform(&transformation);
TestResult::from_bool(dbg!((expected_centre - sphere.centre).norm() < 0.000000001))
}
}

View File

@ -6,7 +6,7 @@ use nalgebra::{Affine3, Point3, Vector2, Vector3};
use std::sync::Arc;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Triangle<T: Real> {
pub vertices: [Point3<T>; 3],
pub normals: [Vector3<T>; 3],
@ -14,18 +14,22 @@ pub struct Triangle<T: Real> {
}
impl<T: Real> Transform<T> for Triangle<T> {
fn transform(&mut self, transformation: &Affine3<T>) -> &Self {
for vertex in self.vertices.iter_mut() {
*vertex = transformation.transform_point(&vertex);
fn transform(&self, transformation: &Affine3<T>) -> Self {
let normal_transformation =
Affine3::from_matrix_unchecked(transformation.inverse().matrix().transpose());
Triangle {
vertices: [
transformation.transform_point(&self.vertices[0]),
transformation.transform_point(&self.vertices[1]),
transformation.transform_point(&self.vertices[2]),
],
normals: [
normal_transformation.transform_vector(&self.normals[0]),
normal_transformation.transform_vector(&self.normals[1]),
normal_transformation.transform_vector(&self.normals[2]),
],
material: Arc::clone(&self.material),
}
let normal_transformation = Affine3::from_matrix_unchecked(dbg!(dbg!(transformation)
.inverse()
.matrix()
.transpose()));
for normal in self.normals.iter_mut() {
*normal = dbg!(normal_transformation.transform_vector(dbg!(&normal)));
}
self
}
}
@ -181,12 +185,12 @@ mod tests {
let n0 = n0.normalize();
let n1 = n1.normalize();
let n2 = n2.normalize();
let mut target = Triangle {
let target = Triangle {
vertices: [v0, v1, v2],
normals: [n0, n1, n2],
material: Arc::new(LambertianMaterial::new_dummy()),
};
target.transform(&Affine3::identity());
let target = target.transform(&Affine3::identity());
target.vertices[0] == v0
&& target.vertices[1] == v1
&& target.vertices[2] == v2
@ -208,13 +212,13 @@ mod tests {
let n0 = n0.normalize();
let n1 = n1.normalize();
let n2 = n2.normalize();
let mut target = Triangle {
let target = Triangle {
vertices: [v0, v1, v2],
normals: [n0, n1, n2],
material: Arc::new(LambertianMaterial::new_dummy()),
};
let transformation = Affine3::identity() * Translation3::from(translation);
target.transform(&transformation);
let target = target.transform(&transformation);
target.normals[0] == n0 && target.normals[1] == n1 && target.normals[2] == n2
}
@ -231,13 +235,13 @@ mod tests {
let n0 = n0.normalize();
let n1 = n1.normalize();
let n2 = n2.normalize();
let mut target = Triangle {
let target = Triangle {
vertices: [v0, v1, v2],
normals: [n0, n1, n2],
material: Arc::new(LambertianMaterial::new_dummy()),
};
let transformation = Affine3::identity() * Translation3::from(translation);
target.transform(&transformation);
let target = target.transform(&transformation);
target.vertices[0] == v0 + translation
&& target.vertices[1] == v1 + translation
&& target.vertices[2] == v2 + translation

View File

@ -0,0 +1,49 @@
use super::{Aggregate, BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
use crate::Real;
impl<T: Real> HasBoundingBox<T> for Vec<Box<dyn Primitive<T>>> {
fn bounding_box(&self) -> BoundingBox<T> {
self.iter().fold(BoundingBox::empty(), |acc, elem| {
acc.union(&elem.bounding_box())
})
}
}
impl<T: Real> Intersect<T> for Vec<Box<dyn Primitive<T>>> {
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
self.iter()
.flat_map(|primitive| primitive.intersect(&ray))
.min_by(
|a, b| match PartialOrd::partial_cmp(&a.distance, &b.distance) {
None => std::cmp::Ordering::Less,
Some(ordering) => ordering,
},
)
}
}
impl<T: Real> Aggregate<T> for Vec<Box<dyn Primitive<T>>> {}
impl<T: Real> HasBoundingBox<T> for Vec<Box<dyn Aggregate<T>>> {
fn bounding_box(&self) -> BoundingBox<T> {
self.iter().fold(BoundingBox::empty(), |acc, elem| {
acc.union(&elem.bounding_box())
})
}
}
impl<T: Real> Intersect<T> for Vec<Box<dyn Aggregate<T>>> {
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
self.iter()
.flat_map(|aggregate| aggregate.intersect(&ray))
.min_by(
|a, b| match PartialOrd::partial_cmp(&a.distance, &b.distance) {
None => std::cmp::Ordering::Less,
Some(ordering) => ordering,
},
)
}
}
impl<T: Real> Aggregate<T> for Vec<Box<dyn Aggregate<T>>> {}

View File

@ -1,9 +1,9 @@
use nalgebra::{Point3};
use crate::raycasting::Primitive;
use crate::raycasting::Aggregate;
use crate::Real;
pub struct Scene<T: Real> {
pub camera_location: Point3<T>,
pub objects: Vec<Box<dyn Primitive<T>>>,
pub objects: Vec<Box<dyn Aggregate<T>>>,
}