diff options
Diffstat (limited to 'src/world')
-rw-r--r-- | src/world/container.rs | 43 | ||||
-rw-r--r-- | src/world/hittable.rs | 33 | ||||
-rw-r--r-- | src/world/mod.rs | 16 | ||||
-rw-r--r-- | src/world/scene.rs | 33 | ||||
-rw-r--r-- | src/world/shapes/sphere.rs | 24 |
5 files changed, 123 insertions, 26 deletions
diff --git a/src/world/container.rs b/src/world/container.rs new file mode 100644 index 0000000..6f8c182 --- /dev/null +++ b/src/world/container.rs @@ -0,0 +1,43 @@ +use super::{Hittable, Intersection}; +use crate::core::Ray; + +pub struct HittableList { + elems: Vec<Box<dyn Hittable>>, +} + +impl HittableList { + pub fn new() -> Self { + Self::default() + } + + pub fn add(&mut self, h: Box<dyn Hittable>) { + self.elems.push(h); + } +} + +impl Hittable for HittableList { + fn intersect(&self, ray: &Ray) -> Option<Intersection> { + let mut min: Option<Intersection> = None; + + for e in self.elems.iter() { + if let Some(i) = e.intersect(&ray) { + match min { + // Do nothing if distance is bigger than min + Some(ref min_i) if min_i.t < i.t => {}, + // If no existing min or closer than + _ => min = Some(i), + } + } + } + + min + } +} + +impl Default for HittableList { + fn default() -> Self { + Self { + elems: Vec::new(), + } + } +} diff --git a/src/world/hittable.rs b/src/world/hittable.rs new file mode 100644 index 0000000..720a019 --- /dev/null +++ b/src/world/hittable.rs @@ -0,0 +1,33 @@ +use crate::core::{Vector3f, Bound3f, Ray}; +use crate::Float; +use crate::material::Material; + +/// Returns the context of a intersection +pub struct Intersection<'a> { + /// Normal vector at intersection + pub n: Vector3f, + pub p: Vector3f, + pub t: Float, + pub m: Option<&'a dyn Material>, +} + +impl Intersection<'_> { + pub fn norm_against_ray(&self, r: &Ray) -> Vector3f { + if self.n.dot(&r.direction) < 0.0 { + self.n + } else { + -self.n + } + } +} + +/// Defines a common trait for objects in the scene +pub trait Hittable: Sync + Send { + /// Returns the intersection with ray + fn intersect(&self, ray: &Ray) -> Option<Intersection>; + + /// Returns the axis alligned bounding box containing self + fn bounding_box(&self) -> Option<Bound3f> { + None + } +} diff --git a/src/world/mod.rs b/src/world/mod.rs index f0ba8d2..43f7530 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -2,11 +2,15 @@ pub mod shapes; mod scene; +mod container; +mod hittable; pub use scene::*; +pub use hittable::{Intersection, Hittable}; +pub use container::HittableList; use std::sync::Arc; -use crate::core::Hittable; use crate::material::Material; +use crate::core::{Bound3f, Ray}; pub struct Object { pub shape: Box<dyn Hittable + Sync>, @@ -21,3 +25,13 @@ impl Object { } } } + +impl Hittable for Object { + fn intersect(&self, ray: &Ray) -> Option<Intersection> { + self.shape.intersect(ray).map(|mut i| {i.m = Some(self.mat.as_ref()); i}) + } + + fn bounding_box(&self) -> Option<Bound3f> { + self.shape.bounding_box() + } +} diff --git a/src/world/scene.rs b/src/world/scene.rs index 444e915..03578be 100644 --- a/src/world/scene.rs +++ b/src/world/scene.rs @@ -1,15 +1,9 @@ -use crate::core::{Ray, Intersection}; -use crate::material::Material; +use crate::core::Ray; -use super::Object; +use super::{Object, HittableList, Hittable, Intersection}; pub struct Scene { - objs: Vec<Object>, -} - -pub struct SceneIntersect<'a> { - pub mat: &'a dyn Material, - pub i: Intersection, + content: HittableList, } impl Scene { @@ -18,7 +12,7 @@ impl Scene { } pub fn add_object(&mut self, obj: Object) { - self.objs.push(obj); + self.content.add(Box::new(obj)); } pub fn add_objects(&mut self, objs: Vec<Object>) { @@ -26,27 +20,18 @@ impl Scene { self.add_object(obj); } } +} - pub fn intersect(&self, ray: &Ray) -> Option<SceneIntersect> { - let mut min: Option<SceneIntersect> = None; - - for obj in self.objs.iter() { - if let Some(i) = obj.shape.intersect(&ray) { - match min { - Some(ref si) if si.i.t < i.t => (), - _ => min = Some(SceneIntersect {i, mat: obj.mat.as_ref() }), - } - } - } - - min +impl Hittable for Scene { + fn intersect(&self, ray: &Ray) -> Option<Intersection> { + self.content.intersect(ray) } } impl Default for Scene { fn default() -> Self { Self { - objs: Vec::new(), + content: HittableList::new(), } } } diff --git a/src/world/shapes/sphere.rs b/src/world/shapes/sphere.rs index 8e0816b..55fc8b4 100644 --- a/src/world/shapes/sphere.rs +++ b/src/world/shapes/sphere.rs @@ -2,7 +2,8 @@ //! //! Spheres are relatively easy to calculate intersections between use crate::Float; -use crate::core::{Ray, Vector3f, Hittable, Intersection}; +use crate::core::{Ray, Vector3f, Bound3f}; +use crate::world::{Hittable, Intersection}; pub struct Sphere { radius: Float, @@ -45,10 +46,31 @@ impl Hittable for Sphere { n: self.norm_at(&w), p: w, t: distance, + m: None, }) } } + + /// Box containing the circle + /// + /// # Examples + /// + /// ``` + /// use rendering::core::{Vector3f, Hittable}; + /// use rendering::world::shapes::Sphere; + /// + /// let sph = Sphere::new(1.0, Vector3f::new(0.0)); + /// let b = sph.bounding_box().unwrap(); + /// + /// assert!(b.min.x == -1.0 && b.min.y == -1.0 && b.min.z == -1.0); + /// assert!(b.max.x == 1.0 && b.max.y == 1.0 && b.max.z == 1.0); + fn bounding_box(&self) -> Option<Bound3f> { + let offset = Vector3f::new(self.radius); + Some( + Bound3f::new(self.center - offset, self.center + offset) + ) + } } #[cfg(test)] |