diff --git a/examples/cornell-box.rs b/examples/cornell-box.rs index d7b75bb..5d482b1 100644 --- a/examples/cornell-box.rs +++ b/examples/cornell-box.rs @@ -2,7 +2,7 @@ use glam::DVec3; use raytracer::{ camera::Camera, material::Material, - shapes::{quad::Quad, sphere::Sphere}, + shapes::{quad::Quad, quad_box::QuadBox, Shapes}, textures::Texture, }; use std::{io, path::Path}; @@ -24,42 +24,53 @@ fn main() -> io::Result<()> { DVec3::new(15., 15., 15.).into(), ); - world.push(Quad::new( + world.push(Shapes::Quad(Quad::new( DVec3::new(555., 0., 0.), DVec3::new(0., 555., 0.), DVec3::new(0., 0., 555.), green, - )); - world.push(Quad::new( + ))); + world.push(Shapes::Quad(Quad::new( DVec3::new(0., 0., 0.), DVec3::new(0., 555., 0.), DVec3::new(0., 0., 555.), red, - )); - world.push(Quad::new( + ))); + world.push(Shapes::Quad(Quad::new( DVec3::new(343., 554., 332.), DVec3::new(-130., 0., 0.), DVec3::new(0., 0., -105.), light, - )); - world.push(Quad::new( + ))); + world.push(Shapes::Quad(Quad::new( DVec3::new(0., 0., 0.), DVec3::new(555., 0., 0.), DVec3::new(0., 0., 555.), white.clone(), - )); - world.push(Quad::new( + ))); + world.push(Shapes::Quad(Quad::new( DVec3::new(555., 555., 555.), DVec3::new(-555., 0., 0.), DVec3::new(0., 0., -555.), white.clone(), - )); - world.push(Quad::new( + ))); + world.push(Shapes::Quad(Quad::new( DVec3::new(0., 0., 555.), DVec3::new(555., 0., 0.), DVec3::new(0., 555., 0.), + white.clone(), + ))); + + world.push(Shapes::QuadBox(QuadBox::new( + DVec3::new(130., 0., 65.), + DVec3::new(295., 165., 230.), + white.clone(), + ))); + world.push(Shapes::QuadBox(QuadBox::new( + DVec3::new(265., 0., 295.), + DVec3::new(430., 330., 460.), white, - )); + ))); let camera = Camera::init() .image_width(800) diff --git a/src/shapes.rs b/src/shapes.rs index 53fa13c..0a85f07 100644 --- a/src/shapes.rs +++ b/src/shapes.rs @@ -1,6 +1,7 @@ use crate::hittable::Hittable; pub mod quad; +pub mod quad_box; pub mod sphere; // are other shapes useful? // possible SDF definitions? @@ -11,6 +12,7 @@ pub mod sphere; pub enum Shapes { Sphere(sphere::Sphere), Quad(quad::Quad), + QuadBox(quad_box::QuadBox), // RoundedBox(rounded_box::RoundedBox), // Box(a_box::Box), // Cylinder(cylinder::Cylinder), @@ -28,6 +30,9 @@ impl Hittable for Shapes { } Shapes::Quad(object) => { object.hit(ray, interval) + } + Shapes::QuadBox(object) => { + object.hit(ray, interval) } // Shapes::RoundedBox(object) => { // object.hit(ray, interval) // } diff --git a/src/shapes/quad_box.rs b/src/shapes/quad_box.rs new file mode 100644 index 0000000..70467a1 --- /dev/null +++ b/src/shapes/quad_box.rs @@ -0,0 +1,104 @@ +use crate::{ + hittable::{HitRecord, Hittable}, + material::Material, + ray::Ray, + textures::Texture, +}; +use glam::DVec3; +use std::{f64::consts::PI, ops::Range}; + +use super::{quad::Quad, Shapes}; + +pub struct QuadBox { + a: DVec3, + b: DVec3, + material: Material, + objects: Vec, +} +impl QuadBox { + pub fn new( + a: DVec3, + b: DVec3, + material: Material, + ) -> Self { + let mut world = vec![]; + + // Returns the 3D box (six sides) that contains the two opposite vertices a & b. + + // Construct the two opposite vertices with the minimum and maximum coordinates. + let min = DVec3::new( + a.x.min(b.x), + a.y.min(b.y), + a.z.min(b.z), + ); + let max = DVec3::new( + a.x.max(b.x), + a.y.max(b.y), + a.z.max(b.z), + ); + + let dx = DVec3::new(max.x - min.x, 0., 0.); + let dy = DVec3::new(0., max.y - min.y, 0.); + let dz = DVec3::new(0., 0., max.z - min.z); + + let front = Quad::new( + DVec3::new(min.x, min.y, max.z), + dx, + dy, + material.clone(), + ); + let right = Quad::new( + DVec3::new(max.x, min.y, max.z), + -dz, + dy, + material.clone(), + ); + let back = Quad::new( + DVec3::new(max.x, min.y, min.z), + -dx, + dy, + material.clone(), + ); + let left = Quad::new( + DVec3::new(min.x, min.y, min.z), + dz, + dy, + material.clone(), + ); + let top = Quad::new( + DVec3::new(min.x, max.y, max.z), + dx, + -dz, + material.clone(), + ); + let bottom = Quad::new( + DVec3::new(min.x, min.y, min.z), + dx, + dz, + material.clone(), + ); + world.push(Shapes::Quad(front)); + world.push(Shapes::Quad(right)); + world.push(Shapes::Quad(back)); + world.push(Shapes::Quad(left)); + world.push(Shapes::Quad(top)); + world.push(Shapes::Quad(bottom)); + + Self { + a, + b, + material, + objects: world, + } + } +} + +impl Hittable for QuadBox { + fn hit( + &self, + ray: &Ray, + interval: Range, + ) -> Option { + self.objects.hit(ray, interval) + } +}