From 429b87e9125666a9fbc0e325c46d5843de055de6 Mon Sep 17 00:00:00 2001 From: "max.nuding" Date: Fri, 8 Jul 2022 13:34:26 +0200 Subject: [PATCH] Add rects --- src/main.rs | 115 +++++++++++++++++++++++++++++++++++++++++++------ src/rect.rs | 88 +++++++++++++++++++++++++++++++++++++ src/xy_rect.rs | 48 --------------------- 3 files changed, 190 insertions(+), 61 deletions(-) create mode 100644 src/rect.rs delete mode 100644 src/xy_rect.rs diff --git a/src/main.rs b/src/main.rs index 635fe97..6ab287c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use crate::image_texture::ImageTexture; use crate::noise::NoiseTexture; use crate::perlin::Perlin; use crate::texture::CheckerTexture; -use crate::xy_rect::XyRect; +use crate::rect::{Plane, Rect2D}; mod vec3; mod ray; @@ -29,13 +29,13 @@ mod texture; mod perlin; mod noise; mod image_texture; -mod xy_rect; +mod rect; // Image const ASPECT_RATIO: f64 = 3.0 / 2.0; -const IMAGE_WIDTH: usize = 400; +const IMAGE_WIDTH: usize = 600; const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize; -const SAMPLES_PER_PIXEL: i32 = 100; +const SAMPLES_PER_PIXEL: i32 = 800; const MAX_DEPTH: i32 = 50; struct Scene { @@ -44,6 +44,93 @@ struct Scene { pub background: Color } +fn cornell_box() -> Scene { + let mut world:HittableList = Vec::new(); + let red = Material::Lambertian( + Lambertian::new(Color::new(0.65, 0.05, 0.05))); + let white = Arc::new(Material::Lambertian( + Lambertian::new(Color::new(0.73, 0.73, 0.73)))); + let green = Material::Lambertian( + Lambertian::new(Color::new(0.12, 0.45, 0.15))); + let light = Material::DiffuseLight( + DiffuseLight::from(Color::new(15.0, 15.0, 15.0))); + world.push(Arc::new(Rect2D::new( + Plane::YZ, + 0.0, + 555.0, + 0.0, + 555.0, + 555.0, + Arc::new(green) + ))); + world.push(Arc::new(Rect2D::new( + Plane::YZ, + 0.0, + 555.0, + 0.0, + 555.0, + 0.0, + Arc::new(red) + ))); + world.push(Arc::new(Rect2D::new( + Plane::XZ, + 213.0, + 343.0, + 227.0, + 332.0, + 554.0, + Arc::new(light) + ))); + world.push(Arc::new(Rect2D::new( + Plane::XZ, + 0.0, + 555.0, + 0.0, + 555.0, + 0.0, + white.clone() + ))); + world.push(Arc::new(Rect2D::new( + Plane::XZ, + 0.0, + 555.0, + 0.0, + 555.0, + 555.0, + white.clone() + ))); + world.push(Arc::new(Rect2D::new( + Plane::XY, + 0.0, + 555.0, + 0.0, + 555.0, + 555.0, + white.clone() + ))); + + let look_from = Point3::new(278.0, 278.0, -800.0); + let look_at = Point3::new(278.0, 278.0, 0.0); + let focus_dist = 2.0; + + let cam = Camera::new( + look_from, + look_at, + Vec3::new(0.0, 1.0, 0.0), + 1.0, + 40.0, + 0.0, + focus_dist, + 0.0, + 1.0); + + Scene { + world, + cam, + background: Color::default() + } +} + fn simple_light() -> Scene { let mut world:HittableList = Vec::new(); @@ -64,14 +151,15 @@ fn simple_light() -> Scene { let difflight = Material::DiffuseLight( // Brighter than 1.0/1.0/1.0 so it can light things DiffuseLight::from(Color::new(4.0, 4.0, 4.0))); - world.push(Arc::new(XyRect { - x0: 3.0, - x1: 5.0, - y0: 1.0, - y1: 3.0, - k: -2.0, - material: Arc::new(difflight) - })); + world.push(Arc::new(Rect2D::new( + Plane::XY, + 3.0, + 5.0, + 1.0, + 3.0, + -2.0, + Arc::new(difflight) + ))); let look_from = Point3::new(26.0, 3.0, 6.0); let look_at = Point3::new(0.0, 2.0, 0.0); @@ -336,13 +424,14 @@ fn random_scene() -> Scene { fn main() { // World - let scene: u8 = 4; + let scene: u8 = 5; let scene_setup = match scene { 0 => two_spheres(), 1 => two_perlin_spheres(), 2 => earth(), 3 => sun(), 4 => simple_light(), + 5 => cornell_box(), _ => random_scene(), }; diff --git a/src/rect.rs b/src/rect.rs new file mode 100644 index 0000000..02998a2 --- /dev/null +++ b/src/rect.rs @@ -0,0 +1,88 @@ +use std::sync::Arc; +use crate::hittable::{HitRecord, Hittable}; +use crate::{Aabb, Material, Point3, Ray, Vec3}; + +pub enum Plane { + XY, + XZ, + YZ +} + +pub struct Rect2D { + plane: Plane, + a0: f64, + a1: f64, + b0: f64, + b1: f64, + k: f64, + material: Arc +} + +impl Rect2D { + pub fn new(plane: Plane, a0: f64, a1: f64, b0: f64, b1: f64, k: f64, material: Arc) -> Self { + Self { plane, a0, a1, b0, b1, k, material } + } +} + +impl Hittable for Rect2D { + fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { + let t = match &self.plane { + Plane::XY => (self.k - ray.origin().z()) / ray.direction().z(), + Plane::XZ => (self.k - ray.origin().y()) / ray.direction().y(), + Plane::YZ => (self.k - ray.origin().x()) / ray.direction().x(), + }; + let (a, b) = match &self.plane { + Plane::XY => ( + ray.origin().x() + t * ray.direction().x(), + ray.origin().y() + t * ray.direction().y()), + Plane::XZ => ( + ray.origin().x() + t * ray.direction().x(), + ray.origin().z() + t * ray.direction().z()), + Plane::YZ => ( + ray.origin().y() + t * ray.direction().y(), + ray.origin().z() + t * ray.direction().z()), + }; + if t < t_min || t > t_max { + return None; + } + if a < self.a0 || a > self.a1 || b < self.b0 || b > self.b1 { + return None; + } + let normal = match &self.plane { + Plane::XY => Vec3::new(0.0, 0.0, 1.0), + Plane::XZ => Vec3::new(0.0, 1.0, 0.0), + Plane::YZ => Vec3::new(1.0, 0.0, 0.0), + }; + let dot = ray.direction().dot(&normal); + let front_face = dot < 0.0; + let normal = if front_face { normal } else { -normal }; + Some(HitRecord { + point: ray.at(t), + normal, + t, + u: (a-self.a0)/(self.a1 -self.a0), + v: (b-self.b0)/(self.b1 -self.b0), + front_face, + material: &self.material + }) + } + + fn bounding_box(&self, _time0: f64, _time1: f64) -> Option { + // The bounding box must have non-zero width in each dimension, so pad the Z + // dimension a small amount. + match &self.plane { + Plane::XY => Some(Aabb { + minimum: Point3::new(self.a0, self.b0, self.k-0.0001), + maximum: Point3::new(self.a1, self.b1, self.k+0.0001), + }), + Plane::XZ=> Some(Aabb { + minimum: Point3::new(self.a0, self.k-0.0001, self.b0), + maximum: Point3::new(self.a1, self.k+0.0001, self.b1), + }), + Plane::YZ => Some(Aabb { + minimum: Point3::new(self.k-0.0001, self.a0, self.b0), + maximum: Point3::new(self.k+0.0001, self.a1, self.b1), + }) + } + } +} diff --git a/src/xy_rect.rs b/src/xy_rect.rs deleted file mode 100644 index 4c5564f..0000000 --- a/src/xy_rect.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::sync::Arc; -use crate::hittable::{HitRecord, Hittable}; -use crate::{Aabb, Material, Point3, Ray, Vec3}; - -pub struct XyRect { - pub x0: f64, - pub x1: f64, - pub y0: f64, - pub y1: f64, - pub k: f64, - pub material: Arc -} - -impl Hittable for XyRect { - fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { - let t = (self.k - ray.origin().z()) / ray.direction().z(); - if t < t_min || t > t_max { - return None; - } - let x = ray.origin().x() + t * ray.direction().x(); - let y = ray.origin().y() + t * ray.direction().y(); - if x < self.x0 || x > self.x1 || y < self.y0 || y > self.y1 { - return None; - } - let normal = Vec3::new(0.0, 0.0, 1.0); - let dot = ray.direction().dot(&normal); - let front_face = dot < 0.0; - let normal = if front_face { normal } else { -normal }; - Some(HitRecord { - point: ray.at(t), - normal, - t, - u: (x-self.x0)/(self.x1-self.x0), - v: (y-self.y0)/(self.y1-self.y0), - front_face, - material: &self.material - }) - } - - fn bounding_box(&self, _time0: f64, _time1: f64) -> Option { - // The bounding box must have non-zero width in each dimension, so pad the Z - // dimension a small amount. - Some(Aabb { - minimum: Point3::new(self.x0, self.y0, self.k-0.0001), - maximum: Point3::new(self.x1, self.y1, self.k+0.0001), - }) - } -}