Big rijiggering of types
This commit is contained in:
parent
01259e1e55
commit
90bb7d84af
|
|
@ -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| {
|
||||
|
|
|
|||
89
src/main.rs
89
src/main.rs
|
|
@ -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,
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>>> {}
|
||||
|
|
@ -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>>>,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue