From 599f484dff588f0e3268f6ff60178d22f82f3a43 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 18 Jul 2021 16:31:07 -0700 Subject: [PATCH] camera: protoype supersampling for rayon render pass. --- rtchallenge/Cargo.lock | 66 +++++++++++++++++++++++++++++++++++++++ rtchallenge/Cargo.toml | 1 + rtchallenge/src/camera.rs | 42 +++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/rtchallenge/Cargo.lock b/rtchallenge/Cargo.lock index 251ac66..798d80e 100644 --- a/rtchallenge/Cargo.lock +++ b/rtchallenge/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" version = "0.15.2" @@ -306,6 +308,17 @@ dependencies = [ "backtrace", ] +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.24.0" @@ -508,6 +521,12 @@ dependencies = [ "miniz_oxide 0.3.7", ] +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -550,6 +569,46 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + [[package]] name = "rayon" version = "1.5.1" @@ -606,6 +665,7 @@ dependencies = [ "enum-utils", "num_cpus", "png", + "rand", "rayon", "serde", "serde_json", @@ -828,6 +888,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "wasm-bindgen" version = "0.2.74" diff --git a/rtchallenge/Cargo.toml b/rtchallenge/Cargo.toml index 68c1e5e..f7035ae 100644 --- a/rtchallenge/Cargo.toml +++ b/rtchallenge/Cargo.toml @@ -16,6 +16,7 @@ criterion = "0.3.4" enum-utils = "0.1.2" num_cpus = "1.13.0" png = "0.16.8" +rand = "0.8.4" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.64" diff --git a/rtchallenge/src/camera.rs b/rtchallenge/src/camera.rs index 8988cf9..bc07f01 100644 --- a/rtchallenge/src/camera.rs +++ b/rtchallenge/src/camera.rs @@ -7,6 +7,7 @@ use std::{ thread, }; +use rand::Rng; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::Deserialize; use structopt::StructOpt; @@ -114,6 +115,31 @@ impl Camera { pub fn pixel_size(&self) -> f32 { self.pixel_size } + pub fn supersample_rays_for_pixel(&self, px: usize, py: usize, samples: usize) -> Vec { + let mut rng = rand::thread_rng(); + + (0..samples) + .map(|_| { + // The offset from the edge of the canvas to the pixel's corner. + let xoffset = (px as f32 + rng.gen::()) * self.pixel_size; + let yoffset = (py as f32 + rng.gen::()) * self.pixel_size; + + // The untransformed coordinates of the pixle in world space. + // (Remember that the camera looks toward -z, so +x is to the left.) + let world_x = self.half_width - xoffset; + let world_y = self.half_height - yoffset; + + // Using the camera matrix, transofmrm the canvas point and the origin, + // and then compute the ray's direction vector. + // (Remember that the canvas is at z>=-1). + let pixel = self.inverse_transform * Tuple::point(world_x, world_y, -1.); + let origin = self.inverse_transform * Tuple::point(0., 0., 0.); + let direction = (pixel - origin).normalize(); + + Ray::new(origin, direction) + }) + .collect() + } /// Calculate ray that starts at the camera and passes through the (x,y) /// pixel on the canvas. @@ -297,9 +323,19 @@ impl Camera { (0..self.vsize).into_par_iter().for_each(|y| { let mut row_image = Canvas::new(self.hsize, 1, BLACK); for x in 0..self.hsize { - let ray = self.ray_for_pixel(x, y); - let color = w.color_at(&ray); - row_image.set(x, 0, color); + const SAMPLES: usize = 0; + if SAMPLES > 0 { + let color = self + .supersample_rays_for_pixel(x, y, SAMPLES) + .iter() + .map(|ray| w.color_at(&ray)) + .fold(BLACK, |acc, c| acc + c); + row_image.set(x, 0, color / SAMPLES as f32); + } else { + let ray = self.ray_for_pixel(x, y); + let color = w.color_at(&ray); + row_image.set(x, 0, color); + } } // TODO(wathiede): create a row based setter for memcpying the row as a whole. let mut image = image_mu.lock().expect("failed to lock image mutex");