From c52d1484518f224f18d532446c598554bdf2f155 Mon Sep 17 00:00:00 2001 From: ishanjain28 Date: Sun, 16 Feb 2020 20:10:56 +0530 Subject: [PATCH] Working on chunk based rendering system --- src/demos/diffuse_materials.rs | 28 +++++++------- src/demos/hitable_sphere.rs | 27 +++++++------ src/demos/linear_gradient_rectangle.rs | 27 ++++++------- src/demos/materials.rs | 26 ++++++------- src/demos/mod.rs | 19 ++++++--- src/demos/simple_antialiasing.rs | 26 ++++++------- src/demos/simple_rectangle.rs | 53 +++++++------------------- src/demos/simple_sphere.rs | 29 +++++++------- src/demos/surface_normal_sphere.rs | 29 +++++++------- 9 files changed, 123 insertions(+), 141 deletions(-) diff --git a/src/demos/diffuse_materials.rs b/src/demos/diffuse_materials.rs index ea62790..5c0ab72 100644 --- a/src/demos/diffuse_materials.rs +++ b/src/demos/diffuse_materials.rs @@ -14,15 +14,14 @@ impl Demo for DiffuseMaterials { "Diffuse Materials" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, samples: u8) { - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; + 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 { list: vec![ @@ -33,7 +32,7 @@ impl Demo for DiffuseMaterials { let camera: Camera = Default::default(); 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); @@ -41,13 +40,11 @@ impl Demo for DiffuseMaterials { 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 r = camera.get_ray(u, v); color += calc_color(r, &world, &mut rng); } color /= samples as f64; - let offset = ((y - j - 1) * x + i) * 4; // Without taking square root of each color, we get a picture that // is quite dark @@ -55,9 +52,10 @@ impl Demo for DiffuseMaterials { // So, IRL, It *should* look a bit lighter in color // To do that, We apply gamma correction by a factor of 2 // which means multiple rgb values by 1/gamma aka 1/2 - buf[offset] = (255.99 * color.r().sqrt()) as u8; - buf[offset + 1] = (255.99 * color.g().sqrt()) as u8; - buf[offset + 2] = (255.99 * color.b().sqrt()) as u8; + 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; } } } diff --git a/src/demos/hitable_sphere.rs b/src/demos/hitable_sphere.rs index 87b8fac..362b1e9 100644 --- a/src/demos/hitable_sphere.rs +++ b/src/demos/hitable_sphere.rs @@ -9,15 +9,14 @@ impl Demo for HitableSphere { "Sphere using Hit table" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, _samples: u8) { - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; + 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 lower_left_corner = Vec3::new(-2.0, -1.0, -1.0); let horizontal = Vec3::new(4.0, 0.0, 0.0); @@ -30,7 +29,7 @@ impl Demo for HitableSphere { 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 { let u = i as f64 / x as f64; @@ -38,10 +37,10 @@ impl Demo for HitableSphere { let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v); let color = calc_color(ray, &world); - let offset = ((y - j - 1) * x + i) * 4; - buf[offset] = (255.99 * color.r()) as u8; - buf[offset + 1] = (255.99 * color.g()) as u8; - buf[offset + 2] = (255.99 * color.b()) as u8; + buffer[offset] = (255.99 * color.r()) as u8; + buffer[offset + 1] = (255.99 * color.g()) as u8; + buffer[offset + 2] = (255.99 * color.b()) as u8; + offset += 4; } } } diff --git a/src/demos/linear_gradient_rectangle.rs b/src/demos/linear_gradient_rectangle.rs index 9a5a5eb..279aeca 100644 --- a/src/demos/linear_gradient_rectangle.rs +++ b/src/demos/linear_gradient_rectangle.rs @@ -10,15 +10,15 @@ impl Demo for LinearGradientRectangle { "Linear Gradient Rectangle" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, _samples: u8) { - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; + 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; + // -2.0 and 4.0 in lower_left_corner and horizontal respectively // because our canvas is in 2:1 ratio let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0); @@ -26,6 +26,7 @@ impl Demo for LinearGradientRectangle { let vertical = Vec3::new(0.0, 2.0, 0.0); let origin = Vec3::new(0.0, 0.0, 0.0); + let mut offset = 0; for j in start_y..start_y + ny { for i in start_x..start_x + nx { let u = i as f64 / x as f64; @@ -33,10 +34,10 @@ impl Demo for LinearGradientRectangle { let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v); let c = color(ray); - let offset = ((y - j - 1) * x + i) * 4; - buf[offset] = (255.99 * c.r()) as u8; - buf[offset + 1] = (255.99 * c.g()) as u8; - buf[offset + 2] = (255.99 * c.b()) as u8; + buffer[offset] = (255.99 * c.r()) as u8; + buffer[offset + 1] = (255.99 * c.g()) as u8; + buffer[offset + 2] = (255.99 * c.b()) as u8; + offset += 4; } } } diff --git a/src/demos/materials.rs b/src/demos/materials.rs index d7eb5be..27a50fe 100644 --- a/src/demos/materials.rs +++ b/src/demos/materials.rs @@ -14,15 +14,14 @@ impl Demo for Materials { "Metal Material" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, samples: u8) { - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; + 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 { list: vec![ @@ -51,6 +50,7 @@ impl Demo for Materials { let camera: Camera = Default::default(); 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 { @@ -64,12 +64,12 @@ impl Demo for Materials { } color /= samples as f64; - let offset = ((y - j - 1) * x + i) * 4; // gamma 2 corrected - buf[offset] = (255.99 * color.r().sqrt()) as u8; - buf[offset + 1] = (255.99 * color.g().sqrt()) as u8; - buf[offset + 2] = (255.99 * color.b().sqrt()) as u8; + 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; } } } diff --git a/src/demos/mod.rs b/src/demos/mod.rs index c5f6491..13d7aa1 100644 --- a/src/demos/mod.rs +++ b/src/demos/mod.rs @@ -30,16 +30,17 @@ pub struct Chunk { ny: usize, start_x: usize, start_y: usize, + buffer: Vec, } -pub trait Demo { +pub trait Demo: std::marker::Sync { fn render(&self, buf: &mut [u8], width: usize, height: usize, samples: u8) { let nx = width / VERTICAL_PARTITION; let ny = height / HORIZONTAL_PARTITION; - let v = (0..VERTICAL_PARTITION).collect::>(); + let mut chunks: Vec = Vec::with_capacity(HORIZONTAL_PARTITION * VERTICAL_PARTITION); - for j in v { + for j in 0..VERTICAL_PARTITION { for i in 0..HORIZONTAL_PARTITION { let start_y = j * ny; let start_x = i * nx; @@ -50,14 +51,20 @@ pub trait Demo { ny, start_x, start_y, + buffer: vec![0; nx * ny * 4], }; - - self.render_chunk(buf, chunk, samples); + chunks.push(chunk); } } + + chunks + .par_iter_mut() + .for_each(|mut chunk| self.render_chunk(&mut chunk, samples)); + + // ((y - j - 1) * x + i) * 4 } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, samples: u8); + fn render_chunk(&self, chunk: &mut Chunk, samples: u8); fn name(&self) -> &'static str; diff --git a/src/demos/simple_antialiasing.rs b/src/demos/simple_antialiasing.rs index 4b0bfe3..ca239ae 100644 --- a/src/demos/simple_antialiasing.rs +++ b/src/demos/simple_antialiasing.rs @@ -12,15 +12,14 @@ impl Demo for SimpleAntialiasing { fn name(&self) -> &'static str { "A simple antialiasing implementation" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, samples: u8) { - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; + 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 { list: vec![ @@ -31,6 +30,7 @@ impl Demo for SimpleAntialiasing { let camera: Camera = Default::default(); 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 { @@ -43,10 +43,10 @@ impl Demo for SimpleAntialiasing { color += calc_color(r, &world); } color /= samples as f64; - let offset = ((y - j - 1) * x + i) * 4; - buf[offset] = (255.99 * color.r()) as u8; - buf[offset + 1] = (255.99 * color.g()) as u8; - buf[offset + 2] = (255.99 * color.b()) as u8; + buffer[offset] = (255.99 * color.r()) as u8; + buffer[offset + 1] = (255.99 * color.g()) as u8; + buffer[offset + 2] = (255.99 * color.b()) as u8; + offset += 4; } } } diff --git a/src/demos/simple_rectangle.rs b/src/demos/simple_rectangle.rs index 062b81b..9a0a511 100644 --- a/src/demos/simple_rectangle.rs +++ b/src/demos/simple_rectangle.rs @@ -1,7 +1,4 @@ -use crate::{ - demos::{Chunk, Demo}, - HORIZONTAL_PARTITION, VERTICAL_PARTITION, -}; +use crate::demos::{Chunk, Demo}; pub struct SimpleRectangle; @@ -10,46 +7,24 @@ impl Demo for SimpleRectangle { "simple_rectangle" } - fn render(&self, buf: &mut [u8], width: usize, height: usize, samples: u8) { - let nx = width / VERTICAL_PARTITION; - let ny = height / HORIZONTAL_PARTITION; + 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; - for j in 0..VERTICAL_PARTITION { - for i in 0..HORIZONTAL_PARTITION { - let start_y = j * ny; - let start_x = i * nx; - let chunk = Chunk { - x: width, - y: height, - nx, - ny, - start_x, - start_y, - }; - - self.render_chunk(buf, chunk, samples); - } - } - } - - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, _samples: u8) { - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; + let mut offset = 0; for j in start_y..start_y + ny { for i in start_x..start_x + nx { let color = [i as f64 / x as f64, j as f64 / y as f64, 0.2]; - let offset = ((y - j - 1) * x + i) * 4; - - buf[offset] = (255.99 * color[0]) as u8; - buf[offset + 1] = (255.99 * color[1]) as u8; - buf[offset + 2] = (255.99 * color[2]) as u8; + buffer[offset] = (255.99 * color[0]) as u8; + buffer[offset + 1] = (255.99 * color[1]) as u8; + buffer[offset + 2] = (255.99 * color[2]) as u8; + offset += 4; } } } diff --git a/src/demos/simple_sphere.rs b/src/demos/simple_sphere.rs index 4cde0ea..339e4b4 100644 --- a/src/demos/simple_sphere.rs +++ b/src/demos/simple_sphere.rs @@ -12,7 +12,15 @@ impl Demo for SimpleSphere { "simple_sphere" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, _ns: u8) { + 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; + // Usually, lower_left_corner should've been -1.0,-1.0,-1.0 and // horizontal should've been 2.0,0.0,0.0 // but we are working with a canvas that is 2:1 in size. @@ -23,20 +31,14 @@ impl Demo for SimpleSphere { // stretched horizontally. // To prevent this from happening, Since our dimensions are in 2:1 ratio, // We adjust the lower_left_corner and horizontal values to scale - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; 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); // Observer's position let origin = Vec3::new(0.0, 0.0, 0.0); + let mut offset = 0; + for j in start_y..start_y + ny { for i in start_x..start_x + nx { // relative offsets @@ -46,11 +48,10 @@ impl Demo for SimpleSphere { let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v); let color = calc_color(ray); - - let offset = ((y - j - 1) * x + i) * 4; - buf[offset] = (255.99 * color.r()) as u8; - buf[offset + 1] = (255.99 * color.g()) as u8; - buf[offset + 2] = (255.99 * color.b()) as u8; + buffer[offset] = (255.99 * color.r()) as u8; + buffer[offset + 1] = (255.99 * color.g()) as u8; + buffer[offset + 2] = (255.99 * color.b()) as u8; + offset += 4; } } } diff --git a/src/demos/surface_normal_sphere.rs b/src/demos/surface_normal_sphere.rs index 3a640ed..5ffb8b3 100644 --- a/src/demos/surface_normal_sphere.rs +++ b/src/demos/surface_normal_sphere.rs @@ -11,7 +11,15 @@ impl Demo for SurfaceNormalSphere { "surface_normal_sphere" } - fn render_chunk(&self, buf: &mut [u8], meta: Chunk, _samples: u8) { + 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; + // Usually, lower_left_corner should've been -1.0,-1.0,-1.0 and // horizontal should've been 2.0,0.0,0.0 // but we are working with a canvas that is 2:1 in size. @@ -22,21 +30,14 @@ impl Demo for SurfaceNormalSphere { // stretched horizontally. // To prevent this from happening, Since our dimensions are in 2:1 ratio, // We adjust the lower_left_corner and horizontal values to scale - let Chunk { - x, - y, - nx, - ny, - start_x, - start_y, - } = meta; - 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); // Observer position let origin = Vec3::new(0.0, 0.0, 0.0); + let mut offset = 0; + for j in start_y..start_y + ny { for i in start_x..start_x + nx { let u = i as f64 / x as f64; @@ -48,10 +49,10 @@ impl Demo for SurfaceNormalSphere { let ig = (255.99 * color.g()) as u8; let ib = (255.99 * color.b()) as u8; - let offset = ((y - j - 1) * x + i) * 4; - buf[offset] = ir; - buf[offset + 1] = ig; - buf[offset + 2] = ib; + buffer[offset] = ir; + buffer[offset + 1] = ig; + buffer[offset + 2] = ib; + offset += 4; } } }