diff --git a/rtchallenge/Cargo.lock b/rtchallenge/Cargo.lock index f005268..3c6a1a4 100644 --- a/rtchallenge/Cargo.lock +++ b/rtchallenge/Cargo.lock @@ -441,6 +441,7 @@ dependencies = [ "anyhow", "criterion", "png", + "rayon", "thiserror", ] diff --git a/rtchallenge/Cargo.toml b/rtchallenge/Cargo.toml index 4bc9440..32b461b 100644 --- a/rtchallenge/Cargo.toml +++ b/rtchallenge/Cargo.toml @@ -10,9 +10,13 @@ edition = "2018" anyhow = "1.0.41" criterion = "0.3.4" png = "0.16.8" +rayon = "1.5.1" thiserror = "1.0.25" [[bench]] name = "matrices" harness = false + +[profile.release] +debug = true \ No newline at end of file diff --git a/rtchallenge/examples/eoc7.rs b/rtchallenge/examples/eoc7.rs index 9c63b31..accbb47 100644 --- a/rtchallenge/examples/eoc7.rs +++ b/rtchallenge/examples/eoc7.rs @@ -25,7 +25,7 @@ fn main() -> Result<()> { let from = Tuple::point(0., 1.5, -5.); let to = Tuple::point(0., 1., 0.); let up = Tuple::point(0., 1., 0.); - camera.transform = view_transform(from, to, up); + camera.set_transform(view_transform(from, to, up)); let mut floor = Sphere::default(); floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.)); diff --git a/rtchallenge/src/camera.rs b/rtchallenge/src/camera.rs index 464e597..a7f3181 100644 --- a/rtchallenge/src/camera.rs +++ b/rtchallenge/src/camera.rs @@ -1,10 +1,15 @@ +use std::sync::Mutex; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + use crate::{canvas::Canvas, matrices::Matrix4x4, rays::Ray, tuples::Tuple, world::World, BLACK}; pub struct Camera { hsize: usize, vsize: usize, field_of_view: f32, - pub transform: Matrix4x4, + transform: Matrix4x4, + inverse_transform: Matrix4x4, pixel_size: f32, half_width: f32, half_height: f32, @@ -50,6 +55,7 @@ impl Camera { vsize, field_of_view, transform: Matrix4x4::identity(), + inverse_transform: Matrix4x4::identity(), pixel_size, half_height, half_width, @@ -67,6 +73,10 @@ impl Camera { pub fn transform(&self) -> Matrix4x4 { self.transform } + pub fn set_transform(&mut self, t: Matrix4x4) { + self.transform = t; + self.inverse_transform = t.inverse(); + } pub fn pixel_size(&self) -> f32 { self.pixel_size } @@ -94,7 +104,7 @@ impl Camera { /// /// // Constructing a ray when the camera is transformed. /// let mut c = Camera::new(201, 101, PI / 2.); - /// c.transform = Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.); + /// c.set_transform(Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.)); /// let r = c.ray_for_pixel(100, 50); /// assert_eq!(r.origin, Tuple::point(0., 2., -5.)); /// assert_eq!( @@ -115,8 +125,8 @@ impl Camera { // Using the camera matrix, transofmrm the canvas point and the origin, // and then compute the ray's direction vector. // (Remember that the canves is at z>=-1). - let pixel = self.transform.inverse() * Tuple::point(world_x, world_y, -1.); - let origin = self.transform.inverse() * Tuple::point(0., 0., 0.); + let pixel = self.inverse_transform * Tuple::point(world_x, world_y, -1.); + let origin = self.inverse_transform * Tuple::point(0., 0., 0.); let direction = (pixel - origin).normalize(); Ray::new(origin, direction) @@ -141,11 +151,37 @@ impl Camera { /// let from = Tuple::point(0., 0., -5.); /// let to = Tuple::point(0., 0., 0.); /// let up = Tuple::vector(0., 1., 0.); - /// c.transform = view_transform(from, to, up); + /// c.set_transform(view_transform(from, to, up)); /// let image = c.render(&w); /// assert_eq!(image.get(5, 5), Color::new(0.38066, 0.47583, 0.2855)); /// ``` pub fn render(&self, w: &World) -> Canvas { + self.render_serial(w) + } + + #[allow(dead_code)] + fn render_parallel(&self, w: &World) -> Canvas { + let image_mu = Mutex::new(Canvas::new(self.hsize, self.vsize, BLACK)); + + (0..self.vsize).into_par_iter().for_each(|y| { + let mut row_image = Canvas::new(self.hsize, 1, BLACK); + for x in 0..self.hsize { + let ray = self.ray_for_pixel(x, y); + let color = w.color_at(&ray); + row_image.set(x, 0, color); + } + // TODO(wathiede): create a row based setter for memcpying the row as a whole. + let mut image = image_mu.lock().expect("failed to lock image mutex"); + for x in 0..self.hsize { + image.set(x, y, row_image.get(x, 0)); + } + }); + image_mu + .into_inner() + .expect("failed to get image out of mutex") + } + + fn render_serial(&self, w: &World) -> Canvas { let mut image = Canvas::new(self.hsize, self.vsize, BLACK); for y in 0..self.vsize { for x in 0..self.hsize {