diff --git a/Cargo.lock b/Cargo.lock index 49cbff7..d22a960 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -666,15 +666,16 @@ version = "0.1.0" dependencies = [ "png", "rand", + "rayon", "sorted-vec", "thousands", ] [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", diff --git a/img/menger_castle_scene.png b/img/menger_castle_scene.png index ed59743..80edf22 100644 Binary files a/img/menger_castle_scene.png and b/img/menger_castle_scene.png differ diff --git a/ray-tracer-cli/src/scenes/menger_scene.rs b/ray-tracer-cli/src/scenes/menger_scene.rs index 3f6a63d..9db8172 100644 --- a/ray-tracer-cli/src/scenes/menger_scene.rs +++ b/ray-tracer-cli/src/scenes/menger_scene.rs @@ -67,7 +67,7 @@ impl Scene for MengerCastleScene { floor.set_material(material_floor.clone()); world.objects.push(floor); - let menger_sponge = MengerSponge::new(3); + let menger_sponge = MengerSponge::new(4); let mut cube = build_cube(); cube.set_transformation(&scaling(2.0, 1.0, 2.0) * &translation(0.0, 1.0, 0.0)); diff --git a/ray-tracer-lib/Cargo.toml b/ray-tracer-lib/Cargo.toml index 0c510be..41966ce 100644 --- a/ray-tracer-lib/Cargo.toml +++ b/ray-tracer-lib/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" sorted-vec = "0.8.3" rand = { version = "0.8.5", features = [] } png = { version = "0.17.11", features = [] } -thousands = {version = "0.2.0"} \ No newline at end of file +thousands = {version = "0.2.0"} +rayon = { version = "1.9.0"} \ No newline at end of file diff --git a/ray-tracer-lib/src/camera.rs b/ray-tracer-lib/src/camera.rs index 8832902..d9ed452 100644 --- a/ray-tracer-lib/src/camera.rs +++ b/ray-tracer-lib/src/camera.rs @@ -1,7 +1,8 @@ use io::stdout; use std::io; use std::io::Write; -use std::sync::atomic::Ordering; +use std::sync::atomic::{AtomicUsize, Ordering}; +use rayon::prelude::*; use crate::canvas::Canvas; use crate::core::math::Float; use crate::core::matrix::Matrix; @@ -10,6 +11,9 @@ use crate::core::tuple::point; use crate::object::{INTERSECTION_COUNTER, OBJECT_COUNTER}; use crate::world::World; use thousands::Separable; +use crate::colors::Color; +use std::time::{Instant}; +use std::sync::{Arc, Mutex}; pub struct Camera { pub h_size: usize, @@ -22,6 +26,20 @@ pub struct Camera { pub inverse_transform: Matrix<4>, } +pub struct Pixel { + x : usize, + y : usize, + color : Color, +} + +pub struct Block { + x_min : usize, + x_max : usize, + y_min : usize, + y_max : usize, + pixels : Vec +} + impl Camera { pub fn new(h_size: usize, v_size: usize, field_of_view: Float) -> Camera { let half_view = (field_of_view / 2.0).tan() as Float; @@ -67,6 +85,62 @@ impl Camera { } pub fn render(&self, world: &World, file_path: &str) -> Canvas { + let mut blocks: Vec = vec![]; + let n = 20; + let nx = self.v_size / n; + let ny = self.h_size / n; + + for i in 0..nx { + for j in 0..ny { + let block = Block { + x_min: usize::min(i * n, self.v_size-1), + x_max: usize::min((i+1) * n, self.v_size-1), + y_min: usize::min(j * n, self.h_size-1), + y_max: usize::min((j+1) * n, self.h_size-1), + pixels: vec![], + }; + blocks.push(block); + } + } + + let num_block = AtomicUsize::new(0); + let num_pixel = AtomicUsize::new(0); + let nb_objects = OBJECT_COUNTER.load(Ordering::Relaxed).separate_with_commas(); + let start = Arc::new(Mutex::new(Instant::now())); + + let mut image = Canvas::new(self.h_size, self.v_size); + blocks.par_iter_mut().for_each(|block| { + num_block.fetch_add(1, Ordering::SeqCst); + for x in block.x_min..block.x_max { + for y in block.y_min..block.y_max { + let ray = self.ray_for_pixel(x, y); + let color = world.color_at(&ray, 5); + let pixel = Pixel { x, y, color }; + block.pixels.push(pixel); + let nb_pixels = num_pixel.fetch_add(1, Ordering::SeqCst); + let mut guard = start.lock().unwrap(); + let t = guard.elapsed().as_secs(); + if t > 1 { + let pct= nb_pixels as f32 / (self.v_size*self.h_size) as f32 * 100.0; + print!("\r{:3.2} % - {} / {} - {} - {} inters - {} Objs, {}", pct, nb_pixels, self.v_size*self.h_size, file_path, INTERSECTION_COUNTER.load(Ordering::Relaxed).separate_with_commas(), OBJECT_COUNTER.load(Ordering::Relaxed).separate_with_commas(), nb_objects); + let _ = stdout().flush(); + *guard = Instant::now(); + } + } + } + }); + + for block in blocks.iter() { + for pixel in block.pixels.iter() { + image.write_pixel(pixel.x, pixel.y, pixel.color); + } + } + + println!(); + image + } + + pub fn _render(&self, world: &World, file_path: &str) -> Canvas { let mut image = Canvas::new(self.h_size, self.v_size); let nb_objects = OBJECT_COUNTER.load(Ordering::Relaxed).separate_with_commas();