From f75d0d2b7dc3a56b9a5b19a7d0f3a8b8208926b5 Mon Sep 17 00:00:00 2001 From: ishanjain28 Date: Wed, 11 Mar 2020 16:09:39 +0530 Subject: [PATCH] Refactored to improve some performance. 1. Removed duplication to increase performance a little bit 2. Fixed some minor rendering related issues 3. Added a Defocus Blur Demo --- src/camera.rs | 62 ++++++++---- src/demos/defocus_blur.rs | 125 +++++++++++++++++++++++++ src/demos/dielectric_material.rs | 33 ++++--- src/demos/diffuse_materials.rs | 27 ++++-- src/demos/hitable_sphere.rs | 25 +++-- src/demos/linear_gradient_rectangle.rs | 11 ++- src/demos/materials.rs | 34 ++++--- src/demos/mod.rs | 87 +++++++++++------ src/demos/positionable_camera.rs | 50 ++++++---- src/demos/simple_antialiasing.rs | 29 ++++-- src/demos/simple_rectangle.rs | 14 ++- src/demos/simple_sphere.rs | 11 ++- src/demos/surface_normal_sphere.rs | 11 ++- src/main.rs | 1 + src/types/hitable.rs | 2 +- src/types/material.rs | 5 +- 16 files changed, 399 insertions(+), 128 deletions(-) create mode 100644 src/demos/defocus_blur.rs diff --git a/src/camera.rs b/src/camera.rs index a70646f..e560ff1 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,10 +1,19 @@ -use crate::types::{Ray, Vec3}; +use { + crate::types::{Ray, Vec3}, + rand::Rng, +}; pub struct Camera { - pub origin: Vec3, - pub horizontal: Vec3, - pub vertical: Vec3, - pub lower_left_corner: Vec3, + origin: Vec3, + horizontal: Vec3, + vertical: Vec3, + lower_left_corner: Vec3, + lens_radius: f64, + + // position vectors + u: Vec3, + v: Vec3, + w: Vec3, } impl Camera { @@ -13,7 +22,15 @@ impl Camera { // look_at is the point where camera is looking // v_up is camera's up vector. i.e. it points upwards from the camera // orthogonal to look_from - look_at vector - pub fn new(look_from: Vec3, look_at: Vec3, v_up: Vec3, vertical_fov: f64, aspect: f64) -> Self { + pub fn new( + look_from: Vec3, + look_at: Vec3, + v_up: Vec3, + vertical_fov: f64, + aspect: f64, + aperture: f64, + focus_distance: f64, + ) -> Self { // convert degree to radian let angle = vertical_fov * std::f64::consts::PI / 180.0; let half_height = (angle / 2.0).tan(); @@ -24,35 +41,42 @@ impl Camera { let u = v_up.cross(&w).unit_vector(); let v = w.cross(&u); - let lower_left_corner = origin - u * half_width - v * half_height - w; + let lower_left_corner = origin + - u * focus_distance * half_width + - v * focus_distance * half_height + - w * focus_distance; let horizontal = u * half_width * 2.0; let vertical = v * half_height * 2.0; + let lens_radius = aperture / 2.0; Self { + lens_radius, lower_left_corner, horizontal, vertical, origin, + u, + v, + w, } } pub fn get_ray(&self, u: f64, v: f64) -> Ray { + let mut rng = rand::thread_rng(); + let rd = random_in_unit_disk(&mut rng) * self.lens_radius; + let offset = self.u * rd.x() + self.v * rd.y(); Ray::new( - self.origin, - self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin, + self.origin + offset, + self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin - offset, ) } } -impl std::default::Default for Camera { - fn default() -> Self { - Camera::new( - Vec3::new(0.0, 0.0, 0.0), - Vec3::new(0.0, 0.0, -1.0), - Vec3::new(0.0, 1.0, 0.0), - 90.0, - // 2:1 aspect ratio width:height - 2.0, - ) +fn random_in_unit_disk(rng: &mut rand::rngs::ThreadRng) -> Vec3 { + let mut p = Vec3::new(rng.gen::(), rng.gen::(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0); + + while p.dot(&p) >= 1.0 { + p = Vec3::new(rng.gen::(), rng.gen::(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0); } + p } diff --git a/src/demos/defocus_blur.rs b/src/demos/defocus_blur.rs new file mode 100644 index 0000000..9c7afbc --- /dev/null +++ b/src/demos/defocus_blur.rs @@ -0,0 +1,125 @@ +use { + crate::{ + demos::{Chunk, Demo}, + types::{ + material::{Dielectric, Lambertian, Metal}, + Hitable, HitableList, Ray, Sphere, Vec3, + }, + Camera, + }, + rand::Rng, +}; + +pub struct DefocusBlur; + +impl Demo for DefocusBlur { + fn name(&self) -> &'static str { + "defocus-blur" + } + + fn world(&self) -> Option { + let radius = (std::f64::consts::PI / 4.0).cos(); + Some(HitableList { + list: vec![ + Box::new(Sphere::with_material( + Vec3::new(-radius, 0.0, -1.0), + radius, + Box::new(Lambertian::new(Vec3::new(0.0, 0.0, 1.0))), + )), + Box::new(Sphere::with_material( + Vec3::new(radius, 0.0, -1.0), + radius, + Box::new(Metal::with_fuzz(Vec3::new(0.5, 0.5, 0.0), 0.2)), + )), + Box::new(Sphere::with_material( + Vec3::new(-3.0 * radius, 0.0, -1.0), + radius, + Box::new(Dielectric::new(1.5)), + )), + Box::new(Sphere::with_material( + Vec3::new(0.0, -100.5, -1.0), + 100.0, + Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))), + )), + ], + }) + } + + fn camera(&self, aspect_ratio: f64) -> Option { + let lookfrom = Vec3::new(3.0, 3.0, 2.0); + let lookat = Vec3::new(0.0, 0.0, -1.0); + let aperture = 2.0; + let distance_to_focus = (lookfrom - lookat).length(); + let camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0.0, 1.0, 0.0), + 20.0, + aspect_ratio, + aperture, + distance_to_focus, + ); + Some(camera) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ) { + let x = chunk.x; + let y = chunk.y; + let nx = chunk.nx; + let ny = chunk.ny; + let start_x = chunk.start_x; + let start_y = chunk.start_y; + let buffer = &mut chunk.buffer; + let camera = camera.unwrap(); + let world = world.unwrap(); + + let mut rng = rand::thread_rng(); + let mut offset = 0; + + for j in start_y..start_y + ny { + for i in start_x..start_x + nx { + let mut color = Vec3::new(0.0, 0.0, 0.0); + for _s in 0..samples { + let u = (i as f64 + rng.gen::()) / x as f64; + let v = (j as f64 + rng.gen::()) / y as f64; + + let ray = camera.get_ray(u, v); + color += calc_color(ray, &world, 0); + } + + color /= samples as f64; + + // gamma 2 corrected + buffer[offset] = (255.99 * color.r().sqrt()) as u8; + buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8; + buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8; + offset += 4; + } + } + } +} + +fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 { + if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) { + if depth >= 50 { + Vec3::new(0.0, 0.0, 0.0) + } else { + let material = hit_rec.material.as_ref(); + if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) { + calc_color(scattered_ray, &world, depth + 1) * attenuation + } else { + Vec3::new(0.0, 0.0, 0.0) + } + } + } else { + let unit_direction = ray.direction().unit_vector(); + let t = 0.5 * (unit_direction.y() + 1.0); + Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t + } +} diff --git a/src/demos/dielectric_material.rs b/src/demos/dielectric_material.rs index cfbe084..4ea9107 100644 --- a/src/demos/dielectric_material.rs +++ b/src/demos/dielectric_material.rs @@ -17,16 +17,8 @@ impl Demo for DielectricMaterial { "dielectric-material" } - fn render_chunk(&self, chunk: &mut Chunk, samples: u8) { - let x = chunk.x; - let y = chunk.y; - let nx = chunk.nx; - let ny = chunk.ny; - let start_x = chunk.start_x; - let start_y = chunk.start_y; - let buffer = &mut chunk.buffer; - - let world = HitableList { + fn world(&self) -> Option { + Some(HitableList { list: vec![ Box::new(Sphere::with_material( Vec3::new(0.0, 0.0, -1.0), @@ -54,9 +46,26 @@ impl Demo for DielectricMaterial { Box::new(Dielectric::new(1.5)), )), ], - }; + }) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ) { + let x = chunk.x; + let y = chunk.y; + let nx = chunk.nx; + let ny = chunk.ny; + let start_x = chunk.start_x; + let start_y = chunk.start_y; + let buffer = &mut chunk.buffer; + let camera = camera.unwrap(); + let world = world.unwrap(); - let camera: Camera = Default::default(); let mut rng = rand::thread_rng(); let mut offset = 0; diff --git a/src/demos/diffuse_materials.rs b/src/demos/diffuse_materials.rs index 4009335..c81589a 100644 --- a/src/demos/diffuse_materials.rs +++ b/src/demos/diffuse_materials.rs @@ -14,7 +14,22 @@ impl Demo for DiffuseMaterials { "diffuse-materials" } - fn render_chunk(&self, chunk: &mut Chunk, samples: u8) { + fn world(&self) -> Option { + Some(HitableList { + list: vec![ + Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)), + Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)), + ], + }) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; @@ -22,15 +37,9 @@ impl Demo for DiffuseMaterials { let start_x = chunk.start_x; let start_y = chunk.start_y; let buffer = &mut chunk.buffer; + let camera = camera.unwrap(); + let world = world.unwrap(); - let world = HitableList { - list: vec![ - Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)), - Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)), - ], - }; - - let camera: Camera = Default::default(); let mut rng = rand::thread_rng(); let mut offset = 0; for j in start_y..start_y + ny { diff --git a/src/demos/hitable_sphere.rs b/src/demos/hitable_sphere.rs index 81ecfdd..3a883c6 100644 --- a/src/demos/hitable_sphere.rs +++ b/src/demos/hitable_sphere.rs @@ -1,6 +1,7 @@ use crate::{ demos::{Chunk, Demo}, types::{Hitable, HitableList, Ray, Sphere, Vec3}, + Camera, }; pub struct HitableSphere; @@ -9,7 +10,22 @@ impl Demo for HitableSphere { "sphere-using-hit-table" } - fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) { + fn world(&self) -> Option { + Some(HitableList { + list: vec![ + Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)), + Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)), + ], + }) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + _camera: Option<&Camera>, + world: Option<&HitableList>, + _samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; @@ -17,18 +33,13 @@ impl Demo for HitableSphere { let start_x = chunk.start_x; let start_y = chunk.start_y; let buffer = &mut chunk.buffer; + let world = world.unwrap(); let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0); let horizontal = Vec3::new(4.0, 0.0, 0.0); let vertical = Vec3::new(0.0, 2.0, 0.0); let origin = Vec3::new(0.0, 0.0, 0.0); - let world = HitableList { - list: vec![ - Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)), - Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)), - ], - }; let mut offset = 0; for j in start_y..start_y + ny { for i in start_x..start_x + nx { diff --git a/src/demos/linear_gradient_rectangle.rs b/src/demos/linear_gradient_rectangle.rs index 30ef268..7b6f437 100644 --- a/src/demos/linear_gradient_rectangle.rs +++ b/src/demos/linear_gradient_rectangle.rs @@ -1,7 +1,8 @@ pub struct LinearGradientRectangle; use crate::{ - types::{Ray, Vec3}, + types::{HitableList, Ray, Vec3}, + Camera, {demos::Chunk, Demo}, }; @@ -10,7 +11,13 @@ impl Demo for LinearGradientRectangle { "linear-gradient-rectangle" } - fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) { + fn render_chunk( + &self, + chunk: &mut Chunk, + _camera: Option<&Camera>, + _world: Option<&HitableList>, + _samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; diff --git a/src/demos/materials.rs b/src/demos/materials.rs index 8e9e80b..f1b6a58 100644 --- a/src/demos/materials.rs +++ b/src/demos/materials.rs @@ -17,16 +17,8 @@ impl Demo for Materials { "metal-material" } - fn render_chunk(&self, chunk: &mut Chunk, samples: u8) { - let x = chunk.x; - let y = chunk.y; - let nx = chunk.nx; - let ny = chunk.ny; - let start_x = chunk.start_x; - let start_y = chunk.start_y; - let buffer = &mut chunk.buffer; - - let world = HitableList { + fn world(&self) -> Option { + Some(HitableList { list: vec![ Box::new(Sphere::with_material( Vec3::new(0.0, 0.0, -1.0), @@ -49,9 +41,25 @@ impl Demo for Materials { Box::new(Metal::with_fuzz(Vec3::new(0.8, 0.8, 0.8), 0.5)), )), ], - }; + }) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ) { + let x = chunk.x; + let y = chunk.y; + let nx = chunk.nx; + let ny = chunk.ny; + let start_x = chunk.start_x; + let start_y = chunk.start_y; + let buffer = &mut chunk.buffer; + let camera = camera.unwrap(); - let camera: Camera = Default::default(); let mut rng = rand::thread_rng(); let mut offset = 0; @@ -63,7 +71,7 @@ impl Demo for Materials { let v = (j as f64 + rng.gen::()) / y as f64; let ray = camera.get_ray(u, v); - color += calc_color(ray, &world, 0); + color += calc_color(ray, world.unwrap(), 0); } color /= samples as f64; diff --git a/src/demos/mod.rs b/src/demos/mod.rs index be77f75..94a08f6 100644 --- a/src/demos/mod.rs +++ b/src/demos/mod.rs @@ -1,3 +1,4 @@ +mod defocus_blur; mod dielectric_material; mod diffuse_materials; mod hitable_sphere; @@ -9,6 +10,7 @@ mod simple_rectangle; mod simple_sphere; mod surface_normal_sphere; +pub use defocus_blur::DefocusBlur; pub use dielectric_material::DielectricMaterial; pub use diffuse_materials::DiffuseMaterials; pub use hitable_sphere::HitableSphere; @@ -21,7 +23,10 @@ pub use simple_sphere::SimpleSphere; pub use surface_normal_sphere::SurfaceNormalSphere; use { - crate::{HORIZONTAL_PARTITION, VERTICAL_PARTITION}, + crate::{ + types::{HitableList, Vec3}, + Camera, HORIZONTAL_PARTITION, VERTICAL_PARTITION, + }, rayon::prelude::*, std::{ fs::File, @@ -45,45 +50,69 @@ pub trait Demo: std::marker::Sync { fn render(&self, buf: &mut Vec, width: usize, height: usize, samples: u8) { let nx = width / VERTICAL_PARTITION; let ny = height / HORIZONTAL_PARTITION; + let world = self.world(); + let camera = self.camera(nx as f64 / ny as f64); let buf = Arc::new(Mutex::new(buf)); - (0..VERTICAL_PARTITION).into_par_iter().for_each(move |j| { + (0..VERTICAL_PARTITION).into_par_iter().for_each(|j| { let buf = buf.clone(); - (0..HORIZONTAL_PARTITION) - .into_par_iter() - .for_each(move |i| { - let start_y = j * ny; - let start_x = i * nx; - let x = width; - let y = height; - let mut chunk = Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - buffer: vec![0; nx * ny * 4], - }; - self.render_chunk(&mut chunk, samples); + (0..HORIZONTAL_PARTITION).into_par_iter().for_each(|i| { + let start_y = j * ny; + let start_x = i * nx; + let x = width; + let y = height; + let mut chunk = Chunk { + x, + y, + nx, + ny, + start_x, + start_y, + buffer: vec![0; nx * ny * 4], + }; + self.render_chunk(&mut chunk, camera.as_ref(), world.as_ref(), samples); - let mut buf = buf.lock().unwrap(); + let mut buf = buf.lock().unwrap(); - let mut temp_offset = 0; - for j in start_y..start_y + ny { - let real_offset = ((y - j - 1) * x + start_x) * 4; + let mut temp_offset = 0; + for j in start_y..start_y + ny { + let real_offset = ((y - j - 1) * x + start_x) * 4; - buf[real_offset..real_offset + nx * 4] - .copy_from_slice(&chunk.buffer[temp_offset..temp_offset + nx * 4]); + buf[real_offset..real_offset + nx * 4] + .copy_from_slice(&chunk.buffer[temp_offset..temp_offset + nx * 4]); - temp_offset += nx * 4; - } - }) + temp_offset += nx * 4; + } + }) }); } - fn render_chunk(&self, chunk: &mut Chunk, samples: u8); + fn world(&self) -> Option { + None + } + + fn camera(&self, aspect_ratio: f64) -> Option { + let lookfrom = Vec3::new(0.0, 0.0, 0.0); + let lookat = Vec3::new(0.0, 0.0, -1.0); + Some(Camera::new( + lookfrom, + lookat, + Vec3::new(0.0, 1.0, 0.0), + 90.0, + aspect_ratio, + 0.0, + 1.0, + )) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ); fn name(&self) -> &'static str; diff --git a/src/demos/positionable_camera.rs b/src/demos/positionable_camera.rs index b13a360..b9847fd 100644 --- a/src/demos/positionable_camera.rs +++ b/src/demos/positionable_camera.rs @@ -17,17 +17,9 @@ impl Demo for PositionableCamera { "positionable-camera" } - fn render_chunk(&self, chunk: &mut Chunk, samples: u8) { - let x = chunk.x; - let y = chunk.y; - let nx = chunk.nx; - let ny = chunk.ny; - let start_x = chunk.start_x; - let start_y = chunk.start_y; - let buffer = &mut chunk.buffer; + fn world(&self) -> Option { let radius = (std::f64::consts::PI / 4.0).cos(); - - let world = HitableList { + Some(HitableList { list: vec![ Box::new(Sphere::with_material( Vec3::new(-radius, 0.0, -1.0), @@ -50,15 +42,39 @@ impl Demo for PositionableCamera { Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))), )), ], - }; + }) + } - let camera = Camera::new( - Vec3::new(-2.0, 2.0, 1.0), - Vec3::new(0.0, 0.0, -1.0), + fn camera(&self, aspect_ratio: f64) -> Option { + let lookfrom = Vec3::new(-2.0, 2.0, 1.0); + let lookat = Vec3::new(0.0, 0.0, -1.0); + Some(Camera::new( + lookfrom, + lookat, Vec3::new(0.0, 1.0, 0.0), 68.0, - nx as f64 / ny as f64, - ); + aspect_ratio, + 0.0, + 1.0, + )) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ) { + let x = chunk.x; + let y = chunk.y; + let nx = chunk.nx; + let ny = chunk.ny; + let start_x = chunk.start_x; + let start_y = chunk.start_y; + let buffer = &mut chunk.buffer; + let camera = camera.unwrap(); + let world = world.unwrap(); let mut rng = rand::thread_rng(); let mut offset = 0; @@ -72,9 +88,7 @@ impl Demo for PositionableCamera { let ray = camera.get_ray(u, v); color += calc_color(ray, &world, 0); } - color /= samples as f64; - // gamma 2 corrected buffer[offset] = (255.99 * color.r().sqrt()) as u8; buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8; diff --git a/src/demos/simple_antialiasing.rs b/src/demos/simple_antialiasing.rs index 1d2b3d6..9b61bee 100644 --- a/src/demos/simple_antialiasing.rs +++ b/src/demos/simple_antialiasing.rs @@ -12,7 +12,23 @@ impl Demo for SimpleAntialiasing { fn name(&self) -> &'static str { "simple-antialiasing" } - fn render_chunk(&self, chunk: &mut Chunk, samples: u8) { + + fn world(&self) -> Option { + Some(HitableList { + list: vec![ + Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)), + Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)), + ], + }) + } + + fn render_chunk( + &self, + chunk: &mut Chunk, + camera: Option<&Camera>, + world: Option<&HitableList>, + samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; @@ -20,15 +36,8 @@ impl Demo for SimpleAntialiasing { let start_x = chunk.start_x; let start_y = chunk.start_y; let buffer = &mut chunk.buffer; + let camera = camera.unwrap(); - let world = HitableList { - list: vec![ - Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)), - Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)), - ], - }; - - let camera: Camera = Default::default(); let mut rng = rand::thread_rng(); let mut offset = 0; @@ -40,7 +49,7 @@ impl Demo for SimpleAntialiasing { let v = (j as f64 + rng.gen::()) / y as f64; let r = camera.get_ray(u, v); - color += calc_color(r, &world); + color += calc_color(r, world.unwrap()); } color /= samples as f64; buffer[offset] = (255.99 * color.r()) as u8; diff --git a/src/demos/simple_rectangle.rs b/src/demos/simple_rectangle.rs index 0cb3a9f..0619504 100644 --- a/src/demos/simple_rectangle.rs +++ b/src/demos/simple_rectangle.rs @@ -1,4 +1,8 @@ -use crate::demos::{Chunk, Demo}; +use crate::{ + demos::{Chunk, Demo}, + types::HitableList, + Camera, +}; pub struct SimpleRectangle; @@ -7,7 +11,13 @@ impl Demo for SimpleRectangle { "simple_rectangle" } - fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) { + fn render_chunk( + &self, + chunk: &mut Chunk, + _camera: Option<&Camera>, + _world: Option<&HitableList>, + _samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; diff --git a/src/demos/simple_sphere.rs b/src/demos/simple_sphere.rs index 339e4b4..ec5fda4 100644 --- a/src/demos/simple_sphere.rs +++ b/src/demos/simple_sphere.rs @@ -1,6 +1,7 @@ use crate::{ demos::{Chunk, Demo}, - types::{Ray, Vec3}, + types::{HitableList, Ray, Vec3}, + Camera, }; const RADIUS: f64 = 0.5; @@ -12,7 +13,13 @@ impl Demo for SimpleSphere { "simple_sphere" } - fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) { + fn render_chunk( + &self, + chunk: &mut Chunk, + _camera: Option<&Camera>, + _world: Option<&HitableList>, + _samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; diff --git a/src/demos/surface_normal_sphere.rs b/src/demos/surface_normal_sphere.rs index 5ffb8b3..c400e75 100644 --- a/src/demos/surface_normal_sphere.rs +++ b/src/demos/surface_normal_sphere.rs @@ -1,6 +1,7 @@ use crate::{ demos::{Chunk, Demo}, - types::{Ray, Vec3}, + types::{HitableList, Ray, Vec3}, + Camera, }; const RADIUS: f64 = 0.5; @@ -11,7 +12,13 @@ impl Demo for SurfaceNormalSphere { "surface_normal_sphere" } - fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) { + fn render_chunk( + &self, + chunk: &mut Chunk, + _camera: Option<&Camera>, + _world: Option<&HitableList>, + _samples: u8, + ) { let x = chunk.x; let y = chunk.y; let nx = chunk.nx; diff --git a/src/main.rs b/src/main.rs index c185ffe..0bedb11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,6 +80,7 @@ fn main() -> Result<(), String> { Some(Keycode::Num8) => active_demo = Box::new(demos::Materials), Some(Keycode::Num9) => active_demo = Box::new(demos::DielectricMaterial), Some(Keycode::Num0) => active_demo = Box::new(demos::PositionableCamera), + Some(Keycode::Minus) => active_demo = Box::new(demos::DefocusBlur), None => unreachable!(), _ => (), }; diff --git a/src/types/hitable.rs b/src/types/hitable.rs index c505832..00ccb1b 100644 --- a/src/types/hitable.rs +++ b/src/types/hitable.rs @@ -21,7 +21,7 @@ pub struct HitRecord<'a> { pub material: Option<&'a Box>, } -pub trait Hitable { +pub trait Hitable: Send + Sync { fn hit(&self, _ray: &Ray, _t_min: f64, _t_max: f64) -> Option { None } diff --git a/src/types/material.rs b/src/types/material.rs index a09240a..f9674fb 100644 --- a/src/types/material.rs +++ b/src/types/material.rs @@ -3,7 +3,7 @@ use { rand::Rng, }; -pub trait Material { +pub trait Material: Send + Sync { fn scatter(&self, ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option); } @@ -106,7 +106,8 @@ impl Material for Dielectric { } } -// Polynomial approximation to figure out reflectivity as the angle changes +// Christophe Schlick's Polynomial approximation to figure out reflectivity as the angle changes +// See Fresnel Equations, https://en.wikipedia.org/wiki/Fresnel_equations fn schlick(cosine: f64, reflection_index: f64) -> f64 { let mut r0 = (1.0 - reflection_index) / (1.0 + reflection_index); r0 = r0 * r0;