diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index 79ef0fb..8b12d51 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -177,21 +177,38 @@ fn trace_pixel(x: usize, y: usize, scene: &Scene) -> Vec3 { ) } +struct PixelRequest { + x: usize, + y: usize, +} + +struct PixelResponse { + x: usize, + y: usize, + pixel: Vec3, +} + fn render_worker( tid: usize, scene: &Scene, - input_chan: channel::Receiver, - output_chan: &channel::Sender<(usize, Vec)>, + input_chan: channel::Receiver, + output_chan: &channel::Sender, ) { - for subsample in input_chan { - let mut pixel_data: Vec = Vec::with_capacity(scene.width * scene.height); - for y in 0..scene.height { - for x in 0..scene.width { - let p = trace_pixel(x, y, scene); - pixel_data.push(p); - } + for req in input_chan { + let mut pixel: Vec3 = Default::default(); + for _ in 0..scene.subsamples { + pixel = pixel + trace_pixel(req.x, req.y, scene); } - output_chan.send((subsample, pixel_data)); + pixel = pixel / scene.subsamples as f32; + // Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 or + // sqrt. + let pixel = Vec3::new(pixel[0].sqrt(), pixel[1].sqrt(), pixel[2].sqrt()); + + output_chan.send(PixelResponse { + x: req.x, + y: req.y, + pixel, + }); } trace!(target: "renderer", "Shutting down worker {}", tid); } @@ -201,65 +218,52 @@ pub fn render( output_dir: &Path, store_intermediate: bool, ) -> std::result::Result<(), std::io::Error> { - let (seq_tx, seq_rx) = channel::unbounded(); - let (pixel_data_tx, pixel_data_rx) = channel::unbounded(); + let (pixel_req_tx, pixel_req_rx) = channel::unbounded(); + let (pixel_resp_tx, pixel_resp_rx) = channel::unbounded(); let scene = sync::Arc::new(scene); for i in 0..num_cpus::get() { let s = sync::Arc::clone(&scene); - let seq_rx = seq_rx.clone(); - let pixel_data_tx = pixel_data_tx.clone(); + let pixel_req_rx = pixel_req_rx.clone(); + let pixel_resp_tx = pixel_resp_tx.clone(); thread::spawn(move || { - render_worker(i, &s, seq_rx, &pixel_data_tx); + render_worker(i, &s, pixel_req_rx, &pixel_resp_tx); }); } - drop(seq_rx); - drop(pixel_data_tx); + drop(pixel_req_rx); + drop(pixel_resp_tx); - (1..=scene.subsamples).for_each(|idx| seq_tx.send(idx)); - drop(seq_tx); - - let mut acc_count = 0; - let mut acc: Vec = Vec::with_capacity(scene.width * scene.height); - for _ in 0..(scene.width * scene.height) { - acc.push(Default::default()); + for y in 0..scene.height { + for x in 0..scene.width { + pixel_req_tx.send(PixelRequest { x, y }); + } } + drop(pixel_req_tx); println!("Rendering with {} subsamples", scene.subsamples); let mut img = RgbImage::new(scene.width as u32, scene.height as u32); - for (_subsample, pixel_data) in pixel_data_rx { - acc_count += 1; - pixel_data.iter().enumerate().for_each(|(idx, p)| { - let x = idx % scene.width; - let y = idx / scene.width; - let y_inv = scene.height - y - 1; - acc[idx] = acc[idx] + *p; - - // Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 or - // sqrt. - let col = acc[idx] / acc_count as f32; - let col = Vec3::new(col[0].sqrt(), col[1].sqrt(), col[2].sqrt()); - img.put_pixel( - x as u32, - y_inv as u32, - image::Rgb([ - (col[0] * 255.).min(255.) as u8, - (col[1] * 255.).min(255.) as u8, - (col[2] * 255.).min(255.) as u8, - ]), - ); - }); - if acc_count % 10 == 0 { - print!("{}", acc_count); - } else { - print!("."); - } - io::stdout().flush().unwrap(); - if store_intermediate { - let path = output_dir.join(format!("iteration{:05}.png", acc_count)); - trace!(target: "renderer", "Saving {}", path.display()); - img.save(&path) - .unwrap_or_else(|_| panic!("Failed save {}", path.display())); + let total = scene.width * scene.height; + let mut last_progress = 1000; + for (i, resp) in pixel_resp_rx.enumerate() { + let y_inv = scene.height - resp.y - 1; + img.put_pixel( + resp.x as u32, + y_inv as u32, + image::Rgb([ + (resp.pixel[0] * 255.).min(255.) as u8, + (resp.pixel[1] * 255.).min(255.) as u8, + (resp.pixel[2] * 255.).min(255.) as u8, + ]), + ); + let progress = 100 * i / total; + if progress != last_progress { + last_progress = progress; + if progress % 10 == 0 { + print!("{}%", progress); + } else { + print!("."); + } + io::stdout().flush().unwrap(); } } println!();