diff --git a/src/bvh.rs b/src/bvh.rs index 9354bbf..d983ff6 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -3,17 +3,19 @@ use nalgebra::{Point3, Vector3}; // BOUNDING BOX ----------------------------------------------------------------- #[derive(Clone)] -pub struct BoundingBox { +pub struct AABB { pub bln: Point3, pub trf: Point3, } -impl BoundingBox { - pub fn new(bln: Point3, trf: Point3) -> Self { +impl AABB { + // New box with respective coordinates + pub fn new(bln: Point3, trf: Point3) -> AABB { let bln = bln + Vector3::new(EPSILON, EPSILON, EPSILON); let trf = trf - Vector3::new(EPSILON, EPSILON, EPSILON); - BoundingBox { bln, trf } + AABB { bln, trf } } + // Intersect bounding box exactly pub fn intersect_bounding_box(&self, ray: &Ray) -> bool { let bln = &self.bln; let trf = &self.trf; @@ -23,6 +25,32 @@ impl BoundingBox { let tmin = t1.inf(&t2).min(); let tmax = t1.sup(&t2).max(); + if tmax >= tmin { + let intersect = ray.at_t(tmin); + + // Check if the intersection is inside the box + if intersect.x > bln.x + || intersect.x < trf.x + || intersect.y > bln.y + || intersect.y < trf.y + || intersect.z > bln.z + || intersect.z < trf.z + { + return true; // Intersection is outside the box + } + } + false + } + // Intersect way with some epsilon term + pub fn intersect_bounding_box_aprox(&self, ray: &Ray) -> bool { + let bln = &self.bln; + let trf = &self.trf; + let t1 = (bln - ray.a).component_div(&ray.b); + let t2 = (trf - ray.a).component_div(&ray.b); + + let tmin = t1.inf(&t2).min(); + let tmax = t1.sup(&t2).max(); + if tmax >= tmin { let intersect = ray.at_t(tmin); @@ -39,8 +67,68 @@ impl BoundingBox { } false } - #[allow(dead_code)] + // Get the center of this bounding box fn get_centroid(&self) -> Point3 { self.bln + (self.trf - self.bln) / 2.0 } + // Make a new AABB that contains both + pub fn join(&self, other: &AABB) -> AABB { + AABB::new( + Point3::new( + self.bln.x.min(other.bln.x), + self.bln.y.min(other.bln.y), + self.bln.z.min(other.bln.z), + ), + Point3::new( + self.trf.x.max(other.trf.x), + self.trf.y.max(other.trf.y), + self.trf.z.max(other.trf.z), + ), + ) + } + //Grow the AABB to contain the cover the point + pub fn grow(&self, other: &Point3) -> AABB { + AABB::new( + Point3::new( + self.bln.x.min(other.x), + self.bln.y.min(other.y), + self.bln.z.min(other.z), + ), + Point3::new( + self.trf.x.max(other.x), + self.trf.y.max(other.y), + self.trf.z.max(other.z), + ), + ) + } + // Size of AABB + pub fn size(&self) -> Vector3 { + self.trf - self.bln + } + //Surface area of AABB + pub fn surface_area(&self) -> f64 { + let size = self.size(); + 2.0 * (size.x * size.y + size.x * size.z + size.y * size.z) + } + // Volume of the AABB + pub fn volume(&self) -> f64 { + let size = self.size(); + size.x * size.y * size.z + } } + +pub enum BVHNode<'a> { + Leaf { + parent: &'a BVHNode<'a>, + bounding_box: AABB, + depth: u32, + }, + Node { + parent: Option<&'a BVHNode<'a>>, + child_l: &'a BVHNode<'a>, + child_r: &'a BVHNode<'a>, + depth: u32, + }, +} + +impl<'a> BVHNode<'a> {} diff --git a/src/primitive.rs b/src/primitive.rs index a11a04c..74ac9a0 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -1,5 +1,5 @@ use crate::{ - bvh::BoundingBox, + bvh::AABB, ray::{Intersection, Ray}, {EPSILON, INFINITY}, }; @@ -21,7 +21,7 @@ pub trait Primitive { pub struct Sphere { position: Point3, radius: f64, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Sphere { @@ -29,7 +29,7 @@ impl Sphere { let radius_vec = Vector3::new(radius, radius, radius); let bln = position - radius_vec; let trf = position + radius_vec; - let bounding_box = BoundingBox::new(bln, trf); + let bounding_box = AABB::new(bln, trf); Rc::new(Sphere { position, radius, @@ -90,7 +90,7 @@ pub struct Circle { radius: f64, normal: Vector3, constant: f64, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Circle { @@ -98,7 +98,7 @@ impl Circle { let radius_vec = Vector3::new(radius, radius, radius); let bln = position - radius_vec; let trf = position + radius_vec; - let bounding_box = BoundingBox::new(bln, trf); + let bounding_box = AABB::new(bln, trf); let normal = normal.normalize(); let constant = normal.dot(&position.coords); @@ -156,7 +156,7 @@ pub struct Cylinder { height: f64, base_circle: Rc, top_circle: Rc, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Cylinder { @@ -178,7 +178,7 @@ impl Cylinder { height, base_circle, top_circle, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } @@ -272,7 +272,7 @@ pub struct Cone { height: f64, constant: f64, circle: Rc, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Cone { @@ -289,7 +289,7 @@ impl Cone { height, constant, circle, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } pub fn unit() -> Rc { @@ -376,7 +376,7 @@ pub struct Rectangle { width_direction: Vector3, width: f64, height: f64, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Rectangle { @@ -398,7 +398,7 @@ impl Rectangle { width_direction: width_direction.normalize(), width, height, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } pub fn unit() -> Rc { @@ -451,7 +451,7 @@ impl Primitive for Rectangle { pub struct Cube { bln: Point3, trf: Point3, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Cube { @@ -459,7 +459,7 @@ impl Cube { Rc::new(Cube { bln, trf, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } @@ -539,7 +539,7 @@ pub struct Triangle { v: Point3, w: Point3, normal: Vector3, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Triangle { @@ -549,7 +549,7 @@ impl Triangle { let normal = uw.cross(&uv).normalize(); let bln = u.inf(&v).inf(&w); let trf = u.sup(&v).sup(&w); - let bounding_box = BoundingBox { bln, trf }; + let bounding_box = AABB { bln, trf }; Rc::new(Triangle { u, v, @@ -617,7 +617,7 @@ impl Primitive for Triangle { #[derive(Clone)] pub struct Mesh { triangles: Vec, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Mesh { @@ -630,7 +630,7 @@ impl Mesh { }) } - fn compute_bounding_box(triangles: &Vec) -> BoundingBox { + fn compute_bounding_box(triangles: &Vec) -> AABB { let mut bln = Point3::new(INFINITY, INFINITY, INFINITY); let mut trf = -bln; for triangle in triangles { @@ -641,7 +641,7 @@ impl Mesh { trf = trf.sup(&triangle.v); trf = trf.sup(&triangle.w); } - BoundingBox { bln, trf } + AABB { bln, trf } } pub fn from_file(filename: &str) -> Rc { @@ -687,7 +687,7 @@ impl Mesh { let normal = uv.cross(&uw).normalize(); let bln = u.inf(&v).inf(&w); let trf = u.sup(&v).sup(&w); - let bounding_box = BoundingBox { bln, trf }; + let bounding_box = AABB { bln, trf }; triangles.push(Triangle { u, v, @@ -737,7 +737,7 @@ impl Primitive for Mesh { pub struct Torus { inner_rad: f64, outer_rad: f64, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Torus { @@ -748,7 +748,7 @@ impl Torus { Rc::new(Torus { inner_rad, outer_rad, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } @@ -865,7 +865,7 @@ pub struct Gnonom { x_cube: Rc, y_cube: Rc, z_cube: Rc, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Gnonom { @@ -884,7 +884,7 @@ impl Gnonom { Point3::new(-Self::GNONOM_WIDTH, -Self::GNONOM_WIDTH, 0.0), Point3::new(Self::GNONOM_WIDTH, Self::GNONOM_WIDTH, Self::GNONOM_LENGTH), ); - let bounding_box = BoundingBox { + let bounding_box = AABB { bln: Point3::new( -Self::GNONOM_WIDTH, -Self::GNONOM_WIDTH, @@ -930,7 +930,7 @@ impl Primitive for Gnonom { // CROSS CAP --------- #[derive(Clone)] pub struct CrossCap { - bounding_box: BoundingBox, + bounding_box: AABB, } impl CrossCap { @@ -939,7 +939,7 @@ impl CrossCap { let trf = Point3::new(1.0, 1.0, 1.0); let bln = Point3::new(-1.0, -1.0, -1.0); Rc::new(CrossCap { - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } @@ -1024,7 +1024,7 @@ impl Primitive for CrossCap { pub struct CrossCap2 { p: f64, q: f64, - bounding_box: BoundingBox, + bounding_box: AABB, } impl CrossCap2 { @@ -1035,7 +1035,7 @@ impl CrossCap2 { Rc::new(CrossCap2 { p, q, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } @@ -1143,7 +1143,7 @@ impl Primitive for CrossCap2 { // Steiner --------- #[derive(Clone)] pub struct Steiner { - bounding_box: BoundingBox, + bounding_box: AABB, } impl Steiner { @@ -1152,7 +1152,7 @@ impl Steiner { let trf = Point3::new(1.0, 1.0, 1.0); let bln = Point3::new(-1.0, -1.0, -1.0); Rc::new(Steiner { - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } @@ -1224,7 +1224,7 @@ impl Primitive for Steiner { // Steiner 2 --------- #[derive(Clone)] pub struct Steiner2 { - bounding_box: BoundingBox, + bounding_box: AABB, } impl Steiner2 { @@ -1233,7 +1233,7 @@ impl Steiner2 { let trf = Point3::new(1.0, 1.0, 1.0); let bln = Point3::new(-1.0, -1.0, -1.0); Rc::new(Steiner2 { - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } @@ -1317,7 +1317,7 @@ impl Primitive for Steiner2 { #[derive(Clone)] pub struct Roman { k: f64, - bounding_box: BoundingBox, + bounding_box: AABB, } impl Roman { @@ -1327,7 +1327,7 @@ impl Roman { let bln = Point3::new(-1.0, -1.0, -1.0); Rc::new(Roman { k, - bounding_box: BoundingBox { bln, trf }, + bounding_box: AABB { bln, trf }, }) } } diff --git a/src/ray.rs b/src/ray.rs index 9b8ee75..6d60594 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -98,6 +98,10 @@ impl Ray { if node.primitive.intersect_bounding_box(&ray) { // Check primitive intersection if let Some(intersect) = node.primitive.intersect_ray(&ray) { + // Dont intersect with itself + if intersect.distance < EPSILON { + continue; + } // Check for closest distance by converting to world coords let intersect = intersect.transform(&node.model, &node.inv_model); let distance = distance(&ray.a, &intersect.point); @@ -134,7 +138,7 @@ impl Ray { depth: u8, ) -> Vector3 { let normal = &intersect.normal; - let point = intersect.point + EPSILON * normal; + let point = intersect.point; let incidence = &ray.b; let material = &node.material;