Working on chunk based rendering system

This commit is contained in:
Ishan Jain 2020-02-16 20:10:56 +05:30
parent cae95b0bf0
commit c52d148451
9 changed files with 123 additions and 141 deletions

View File

@ -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::<f64>()) / x as f64;
let v = (j as f64 + rng.gen::<f64>()) / 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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -30,16 +30,17 @@ pub struct Chunk {
ny: usize,
start_x: usize,
start_y: usize,
buffer: Vec<u8>,
}
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::<Vec<usize>>();
let mut chunks: Vec<Chunk> = 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;

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}