From 3f78cacdd93036dbd51bae77d5d8e5430a0bc75f Mon Sep 17 00:00:00 2001 From: Julian T Date: Sat, 6 Mar 2021 16:15:26 +0100 Subject: Several changes to bounding boxes For instance removed support for shapes without a bounding box, such as planes --- src/core/bound3.rs | 54 +++++++++++++++++++++++++++++++++++++++---- src/lib.rs | 1 + src/world/container.rs | 43 ---------------------------------- src/world/container/list.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++ src/world/container/mod.rs | 3 +++ src/world/hittable.rs | 4 +--- src/world/mod.rs | 5 ++-- src/world/scene.rs | 14 ++++++++---- src/world/shapes/sphere.rs | 13 +++++------ 9 files changed, 128 insertions(+), 65 deletions(-) delete mode 100644 src/world/container.rs create mode 100644 src/world/container/list.rs create mode 100644 src/world/container/mod.rs diff --git a/src/core/bound3.rs b/src/core/bound3.rs index 7f54e03..ce6bb09 100644 --- a/src/core/bound3.rs +++ b/src/core/bound3.rs @@ -1,6 +1,6 @@ //! Implements 3d axis aligned bounding box use crate::{Number, Float}; -use super::vector3::Vector3; +use super::vector3::{Vector3, Vector3f}; use crate::core::{min, max}; use crate::core::Ray; @@ -29,23 +29,64 @@ impl Bound3 { Self {min, max} } + + pub fn combine(&self, op: &Self) -> Self { + let min = Vector3::new_xyz( + min(self.min.x, op.min.x), + min(self.min.y, op.min.y), + min(self.min.z, op.min.z) + ); + let max = Vector3::new_xyz( + max(self.max.x, op.max.x), + max(self.max.y, op.max.y), + max(self.max.z, op.max.z) + ); + + Self {min, max} + } + + pub fn and(&self, op: &Self) -> Self { + let min_b = Vector3::new_xyz( + max(self.min.x, op.min.x), + max(self.min.y, op.min.y), + max(self.min.z, op.min.z) + ); + let max_b = Vector3::new_xyz( + min(self.max.x, op.max.x), + min(self.max.y, op.max.y), + min(self.max.z, op.max.z) + ); + + Self {min: min_b, max: max_b} + } + + pub fn area(&self) -> T { + let diag = self.max - self.min; + diag.x * diag.y * diag.z + } } impl Bound3f { + pub const EMPTY: Bound3f = Bound3f{min: Vector3f::ZERO, max: Vector3f::ZERO}; + /// Calculate whether there is a intersect between a bounding box and a ray /// /// # Examples: /// /// ``` /// use rendering::core::{Bound3f, Vector3f, Ray}; + /// use rendering::INFTY; /// let b = Bound3f::new(Vector3f::new(7.0), Vector3f::new(10.0)); /// let r1 = Ray::new_to(Vector3f::new(0.0), Vector3f::new(5.0)); + /// let r2 = Ray::new_to(Vector3f::new(-0.0), Vector3f::new(-5.0)); /// let r3 = Ray::new(Vector3f::new_xyz(-1.0, 0.0, 0.0), Vector3f::new_xyz(1.0, 0.0, 0.0)); /// - /// assert!(b.intersect(&r1)); - /// assert!(!b.intersect(&r3)); + /// assert!(b.intersect(&r1, 0.0, INFTY)); + /// assert!(!b.intersect(&r2, 0.0, INFTY)); + /// assert!(!b.intersect(&r3, 0.0, INFTY)); /// ``` - pub fn intersect(&self, ray: &Ray) -> bool { + pub fn intersect(&self, ray: &Ray, t_min: Float, t_max: Float) -> bool { + println!("BIN: {} -> {}", self.min, self.max); // Method stolen from Ray tracing the next week. // They mention its from pixar for i in 0..3 { @@ -59,7 +100,10 @@ impl Bound3f { t1 = tmp; } - if t1 <= t0 { + let t_min = max(t0, t_min); + let t_max = min(t1, t_max); + + if t_max <= t_min { return false; } } diff --git a/src/lib.rs b/src/lib.rs index a40e8e6..0e6674d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,3 +38,4 @@ pub type Float = f64; pub const M_PI: Float = PI; pub const NEAR_ZERO: Float = 1e-8; +pub const INFTY: Float = f64::INFINITY; diff --git a/src/world/container.rs b/src/world/container.rs deleted file mode 100644 index 6f8c182..0000000 --- a/src/world/container.rs +++ /dev/null @@ -1,43 +0,0 @@ -use super::{Hittable, Intersection}; -use crate::core::Ray; - -pub struct HittableList { - elems: Vec>, -} - -impl HittableList { - pub fn new() -> Self { - Self::default() - } - - pub fn add(&mut self, h: Box) { - self.elems.push(h); - } -} - -impl Hittable for HittableList { - fn intersect(&self, ray: &Ray) -> Option { - let mut min: Option = 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/container/list.rs b/src/world/container/list.rs new file mode 100644 index 0000000..c8e3fdd --- /dev/null +++ b/src/world/container/list.rs @@ -0,0 +1,56 @@ +use crate::world::{Hittable, Intersection}; +use crate::core::{Bound3f, Ray}; + + +pub struct HittableList { + elems: Vec>, +} + +impl HittableList { + pub fn new() -> Self { + Self::default() + } + + pub fn add(&mut self, h: Box) { + self.elems.push(h); + } +} + +impl Hittable for HittableList { + fn intersect(&self, ray: &Ray) -> Option { + let mut min: Option = 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 + } + + fn bounding_box(&self) -> Bound3f { + let mut bound: Bound3f = Bound3f::EMPTY; + + for e in self.elems.iter() { + let eb = e.bounding_box(); + bound = bound.combine(&eb); + } + + bound + } +} + +impl Default for HittableList { + fn default() -> Self { + Self { + elems: Vec::new(), + } + } +} + diff --git a/src/world/container/mod.rs b/src/world/container/mod.rs new file mode 100644 index 0000000..35d4693 --- /dev/null +++ b/src/world/container/mod.rs @@ -0,0 +1,3 @@ +mod list; + +pub use list::HittableList; diff --git a/src/world/hittable.rs b/src/world/hittable.rs index 720a019..c5a353e 100644 --- a/src/world/hittable.rs +++ b/src/world/hittable.rs @@ -27,7 +27,5 @@ pub trait Hittable: Sync + Send { fn intersect(&self, ray: &Ray) -> Option; /// Returns the axis alligned bounding box containing self - fn bounding_box(&self) -> Option { - None - } + fn bounding_box(&self) -> Bound3f; } diff --git a/src/world/mod.rs b/src/world/mod.rs index 43f7530..53d8ad3 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -2,11 +2,10 @@ pub mod shapes; mod scene; -mod container; +pub mod container; mod hittable; pub use scene::*; pub use hittable::{Intersection, Hittable}; -pub use container::HittableList; use std::sync::Arc; use crate::material::Material; @@ -31,7 +30,7 @@ impl Hittable for Object { self.shape.intersect(ray).map(|mut i| {i.m = Some(self.mat.as_ref()); i}) } - fn bounding_box(&self) -> Option { + fn bounding_box(&self) -> Bound3f { self.shape.bounding_box() } } diff --git a/src/world/scene.rs b/src/world/scene.rs index 03578be..6d15fc1 100644 --- a/src/world/scene.rs +++ b/src/world/scene.rs @@ -1,9 +1,11 @@ -use crate::core::Ray; +use crate::core::{Bound3f, Ray}; -use super::{Object, HittableList, Hittable, Intersection}; +use super::{Object, container, Hittable, Intersection}; + +type Container = container::HittableList; pub struct Scene { - content: HittableList, + content: Container, } impl Scene { @@ -26,12 +28,16 @@ impl Hittable for Scene { fn intersect(&self, ray: &Ray) -> Option { self.content.intersect(ray) } + + fn bounding_box(&self) -> Bound3f { + self.content.bounding_box() + } } impl Default for Scene { fn default() -> Self { Self { - content: HittableList::new(), + content: Container::new(), } } } diff --git a/src/world/shapes/sphere.rs b/src/world/shapes/sphere.rs index 55fc8b4..e3348de 100644 --- a/src/world/shapes/sphere.rs +++ b/src/world/shapes/sphere.rs @@ -57,19 +57,18 @@ impl Hittable for Sphere { /// # Examples /// /// ``` - /// use rendering::core::{Vector3f, Hittable}; - /// use rendering::world::shapes::Sphere; + /// use rendering::core::Vector3f; + /// use rendering::world::{Hittable, shapes::Sphere}; /// /// let sph = Sphere::new(1.0, Vector3f::new(0.0)); - /// let b = sph.bounding_box().unwrap(); + /// let b = sph.bounding_box(); /// /// 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 { + fn bounding_box(&self) -> Bound3f { let offset = Vector3f::new(self.radius); - Some( - Bound3f::new(self.center - offset, self.center + offset) - ) + + Bound3f::new(self.center - offset, self.center + offset) } } -- cgit v1.2.3