wip: parallelization
This commit is contained in:
1 parent
eb90c36ae8
commit
10f9c0984d
23 files changed
+294
-211
No files matched your search
@@ -0,0 +1,96 @@
|
||||
use image::{ExtendedColorType, ImageEncoder, codecs::png::PngEncoder};
|
||||
use log::{error, info};
|
||||
use rayon::iter::IntoParallelIterator;
|
||||
use rayon::prelude::*;
|
||||
use std::{fs::File, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
objects::{hit::Hit, traits::Hittable},
|
||||
ray::Ray,
|
||||
scenes::scene::Scene,
|
||||
vec3::Colour,
|
||||
};
|
||||
|
||||
pub fn write_image(filename: &str, pixels: &[u8], width: u32, height: u32) {
|
||||
match File::create(filename) {
|
||||
Ok(out) => {
|
||||
let enc = PngEncoder::new(out);
|
||||
if let Err(e) = enc.write_image(pixels, width, height, ExtendedColorType::Rgb8) {
|
||||
error!("Failed writing image: {}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => error!("Failed to create image file: {} ", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(scene: &mut Scene) {
|
||||
let camera = &mut scene.camera;
|
||||
camera.init(scene.image_width as f32, scene.image_height as f32);
|
||||
|
||||
// TODO: currently splits per vertical line, but could be more granular (per chunk)
|
||||
let mut pixels = vec![0 as u8; (scene.image_width * scene.image_height * 3) as usize];
|
||||
let scanlines: Vec<(usize, &mut [u8])> = pixels
|
||||
.chunks_mut(scene.image_width as usize * 3)
|
||||
.enumerate()
|
||||
.collect();
|
||||
|
||||
scanlines.into_par_iter().for_each(|(i, chunk)| {
|
||||
render_chunk(chunk, scene, i as u32);
|
||||
});
|
||||
|
||||
info!("Writing image file...");
|
||||
write_image(
|
||||
&scene.filename,
|
||||
&pixels,
|
||||
scene.image_width,
|
||||
scene.image_height,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn render_chunk(chunk: &mut [u8], scene: &Scene, y: u32) {
|
||||
let camera = &scene.camera;
|
||||
|
||||
for i in 0..scene.image_width {
|
||||
let pixel_tl = camera.pixel00_loc + (i * camera.pixel_delta_u) + (y * camera.pixel_delta_v);
|
||||
// THOUGHT: the above seems more efficient (esp for larger aa rates) but can test for a
|
||||
// get_ray_no_tl() function and compare performance.
|
||||
|
||||
let mut pixel_colour = Colour::default();
|
||||
for y in 1..(camera.anti_alias_rate + 1) {
|
||||
for x in 1..(camera.anti_alias_rate + 1) {
|
||||
let r = camera.get_ray(pixel_tl, x, y);
|
||||
pixel_colour += ray_colour(&scene.objects, &r, scene.max_depth);
|
||||
}
|
||||
}
|
||||
|
||||
let (r, g, b) =
|
||||
(pixel_colour / (camera.anti_alias_rate * camera.anti_alias_rate) as f32).output();
|
||||
chunk[(i * 3) as usize] = r;
|
||||
chunk[(i * 3) as usize + 1] = g;
|
||||
chunk[(i * 3) as usize + 2] = b;
|
||||
}
|
||||
info!("Line {} finished.", y);
|
||||
}
|
||||
|
||||
pub fn ray_colour(hittables: &Vec<Arc<dyn Hittable>>, r: &Ray, depth: u32) -> Colour {
|
||||
if depth == 0 {
|
||||
return Colour::default();
|
||||
}
|
||||
|
||||
let closest = Hit::hit_list(hittables, r);
|
||||
if let Some(hit) = closest {
|
||||
if let Some((scattered, att)) = hit.mat().scatter(&hit, r) {
|
||||
if let Some(ray) = scattered {
|
||||
return att * ray_colour(hittables, &ray, depth - 1);
|
||||
}
|
||||
return att;
|
||||
}
|
||||
return Colour::default();
|
||||
}
|
||||
|
||||
// background
|
||||
let unit_dir = r.dir().get_unit();
|
||||
let a = 0.5 * (unit_dir.y() + 1.);
|
||||
|
||||
(1.0 - a) * Colour::new(1., 1., 1.) + a * Colour::new(0.5, 0.7, 1.0)
|
||||
}
|
||||