From 9ce878a47a22e3ac9646b963db6fa95a30c81aaf Mon Sep 17 00:00:00 2001 From: "max.nuding" Date: Fri, 8 Jul 2022 14:31:32 +0200 Subject: [PATCH] Add cuboids, fox aspect raio --- src/camera.rs | 2 ++ src/cuboid.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 31 ++++++++++++++---- src/ray.rs | 32 +------------------ 4 files changed, 115 insertions(+), 38 deletions(-) create mode 100644 src/cuboid.rs diff --git a/src/camera.rs b/src/camera.rs index 29a49f0..8ff2e48 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -87,4 +87,6 @@ impl Camera { time1 } } + + pub fn aspect_ratio(&self) -> f64 { self.aspect_ratio } } diff --git a/src/cuboid.rs b/src/cuboid.rs new file mode 100644 index 0000000..915577e --- /dev/null +++ b/src/cuboid.rs @@ -0,0 +1,88 @@ +use std::sync::Arc; +use crate::{Aabb, HittableList, Material, Plane, Point3, Ray, Rect2D}; +use crate::hittable::{HitRecord, Hittable}; + +pub struct Cuboid { + minimum: Point3, + maximum: Point3, + sides: HittableList +} + +impl Cuboid { + pub fn new(p0: Point3, p1: Point3, material: Arc) -> Self { + let mut sides: HittableList = Vec::with_capacity(6); + sides.push(Arc::new(Rect2D::new( + Plane::XY, + p0.x(), + p1.x(), + p0.y(), + p1.y(), + p1.z(), + material.clone() + ))); + sides.push(Arc::new(Rect2D::new( + Plane::XY, + p0.x(), + p1.x(), + p0.y(), + p1.y(), + p0.z(), + material.clone() + ))); + sides.push(Arc::new(Rect2D::new( + Plane::XZ, + p0.x(), + p1.x(), + p0.z(), + p1.z(), + p1.y(), + material.clone() + ))); + sides.push(Arc::new(Rect2D::new( + Plane::XZ, + p0.x(), + p1.x(), + p0.z(), + p1.z(), + p0.y(), + material.clone() + ))); + sides.push(Arc::new(Rect2D::new( + Plane::YZ, + p0.y(), + p1.y(), + p0.z(), + p1.z(), + p1.x(), + material.clone() + ))); + sides.push(Arc::new(Rect2D::new( + Plane::YZ, + p0.y(), + p1.y(), + p0.z(), + p1.z(), + p0.x(), + material.clone() + ))); + + Cuboid { + minimum: p0, + maximum: p1, + sides + } + } +} + +impl Hittable for Cuboid { + fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { + ray.hit_world(&self.sides, t_min, t_max) + } + + fn bounding_box(&self, _time0: f64, _time1: f64) -> Option { + Some(Aabb { + minimum: self.minimum, + maximum: self.maximum + }) + } +} diff --git a/src/main.rs b/src/main.rs index 57135db..ed3bcb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use rand::distributions::{Distribution, Uniform}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use crate::material::{Dielectric, DiffuseLight, Lambertian, Material, Metal}; use crate::aabb::Aabb; +use crate::cuboid::Cuboid; use crate::image_texture::ImageTexture; use crate::noise::NoiseTexture; use crate::perlin::Perlin; @@ -30,11 +31,11 @@ mod perlin; mod noise; mod image_texture; mod rect; +mod cuboid; // Image const ASPECT_RATIO: f64 = 3.0 / 2.0; const IMAGE_WIDTH: usize = 600; -const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize; const SAMPLES_PER_PIXEL: i32 = 100; const MAX_DEPTH: i32 = 50; @@ -54,6 +55,8 @@ fn cornell_box() -> Scene { Lambertian::from(Color::new(0.12, 0.45, 0.15))); let light = Material::DiffuseLight( DiffuseLight::from(Color::new(15.0, 15.0, 15.0))); + + // Walls world.push(Arc::new(Rect2D::new( Plane::YZ, 0.0, @@ -109,6 +112,19 @@ fn cornell_box() -> Scene { white.clone() ))); + // Boxes + world.push(Arc::new(Cuboid::new( + Point3::new(130.0, 0.0, 65.0), + Point3::new(295.0, 165.0, 230.0), + white.clone() + ))); + world.push(Arc::new(Cuboid::new( + Point3::new(265.0, 0.0, 295.0), + Point3::new(430.0, 330.0, 460.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; @@ -438,18 +454,19 @@ fn main() { let between = Uniform::from(0.0..1.0); let start = Instant::now(); - let mut pixels = vec![0; IMAGE_WIDTH * IMAGE_HEIGHT * 3]; + let image_height: usize = (IMAGE_WIDTH as f64 / scene_setup.cam.aspect_ratio()) as usize; + let mut pixels = vec![0; IMAGE_WIDTH * image_height * 3]; let bands: Vec<(usize, &mut [u8])> = pixels.chunks_mut(3).enumerate().collect(); let count = Mutex::new(0); bands.into_par_iter().for_each(|(i, pixel)| { - let row = IMAGE_HEIGHT - (i / IMAGE_WIDTH) - 1; + let row = image_height - (i / IMAGE_WIDTH) - 1; let col = i % IMAGE_WIDTH; let mut rng = rand::thread_rng(); let mut color = Color::default(); (0..SAMPLES_PER_PIXEL).for_each(|_s| { let random_number = between.sample(&mut rng); let u = (col as f64 + random_number) / (IMAGE_WIDTH - 1) as f64; - let v = (row as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64; + let v = (row as f64 + random_number) / (image_height - 1) as f64; let ray = scene_setup.cam.get_ray(u, v); color += ray.pixel_color(scene_setup.background, &scene_setup.world, MAX_DEPTH); }); @@ -459,15 +476,15 @@ fn main() { pixel[2] = bytes[2]; if i % 100 == 0 { let mut rem = count.lock().unwrap(); - let percent_done_before = 100 * *rem / (IMAGE_WIDTH * IMAGE_HEIGHT); + let percent_done_before = 100 * *rem / (IMAGE_WIDTH * image_height); *rem += 100; - let percent_done_after = 100 * *rem / (IMAGE_WIDTH * IMAGE_HEIGHT); + let percent_done_after = 100 * *rem / (IMAGE_WIDTH * image_height); if percent_done_before != percent_done_after { eprint!("\rProgress: {}% ", percent_done_after); } } }); - PNG::write("imc.png", &pixels, IMAGE_WIDTH, IMAGE_HEIGHT).expect("Error writing image: {}"); + PNG::write("imc.png", &pixels, IMAGE_WIDTH, image_height).expect("Error writing image: {}"); eprintln!("\nDone. Time: {}ms", start.elapsed().as_millis()); } diff --git a/src/ray.rs b/src/ray.rs index 7ca4a06..4352b4f 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -29,36 +29,6 @@ impl Ray { if depth <= 0 { return Color::default(); } - /* - if let Some(rect) = self.hit_world(world, 0.001, f64::INFINITY) { - let scattered = rect.material.scatter(self, &rect); - return match scattered { - Some((scattered_ray, albedo)) => { - match scattered_ray { - Some(sr) => { - albedo * sr.pixel_color(background, world, depth-1) - }, - None => albedo - } - }, - None => { return background } - }; - - } else { - let unit_direction = self.direction().unit_vector(); - let t = 0.5 * (unit_direction.y() + 1.0); - return (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0); - //return background; - } - - //Hot nothing, display sky color - let unit_direction = self.direction().unit_vector(); - let t = 0.5 * (unit_direction.y() + 1.0); - (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0) - //return background; - - */ - match self.hit_world(world, 0.001, f64::INFINITY) { Some(rect) => { let scattered = rect.material.scatter(self, &rect); @@ -78,7 +48,7 @@ impl Ray { None => background } } - fn hit_world<'material>( + pub fn hit_world<'material>( &self, world: &'material HittableList, t_min: f64,