camera: make supersampling configurable, wire it up in eoc8.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Bill Thiede 2021-07-18 20:30:06 -07:00
parent c4f10126e3
commit 839642b886
2 changed files with 34 additions and 21 deletions

View File

@ -22,6 +22,10 @@ use rtchallenge::{
struct Opt {
#[structopt(long, default_value = "rayon")]
render_strategy: RenderStrategy,
/// Number of samples per pixel. 0 renders from the center of the pixel, 1 or more samples N
/// times randomly across the pixel.
#[structopt(short, long, default_value = "0")]
samples: usize,
}
fn main() -> Result<()> {
@ -38,6 +42,7 @@ fn main() -> Result<()> {
let up = Tuple::point(0., 1., 0.);
camera.set_transform(view_transform(from, to, up));
camera.render_strategy = opt.render_strategy;
camera.samples_per_pixel = opt.samples;
let mut floor = Sphere::default();
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));

View File

@ -13,7 +13,12 @@ use serde::Deserialize;
use structopt::StructOpt;
use crate::{
canvas::Canvas, matrices::Matrix4x4, rays::Ray, tuples::Tuple, world::World, Float, BLACK,
canvas::Canvas,
matrices::Matrix4x4,
rays::Ray,
tuples::{Color, Tuple},
world::World,
Float, BLACK,
};
#[derive(Copy, Clone, StructOpt, Debug, Deserialize)]
@ -41,6 +46,8 @@ pub struct Camera {
half_width: Float,
half_height: Float,
pub render_strategy: RenderStrategy,
/// 0 renders from the center of the pixel, 1 or higher is random sampling of the pixel.
pub samples_per_pixel: usize,
}
enum Request {
@ -94,6 +101,7 @@ impl Camera {
half_height,
half_width,
render_strategy: RenderStrategy::Rayon,
samples_per_pixel: 0,
}
}
pub fn hsize(&self) -> usize {
@ -275,7 +283,7 @@ impl Camera {
let pixel_resp_tx = pixel_resp_tx.clone();
thread::spawn(move || {
core_affinity::set_for_current(id);
render_worker(&c, &w, pixel_req_rx, &pixel_resp_tx);
render_worker_task(&c, &w, pixel_req_rx, &pixel_resp_tx);
})
})
.collect::<Vec<_>>();
@ -322,19 +330,8 @@ 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 {
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 Float);
} else {
let ray = self.ray_for_pixel(x, y);
let color = w.color_at(&ray);
row_image.set(x, 0, color);
}
let color = self.sample(w, x, y);
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");
@ -352,16 +349,28 @@ impl Camera {
let mut image = Canvas::new(self.hsize, self.vsize, BLACK);
for y in 0..self.vsize {
for x in 0..self.hsize {
let ray = self.ray_for_pixel(x, y);
let color = w.color_at(&ray);
let color = self.sample(w, x, y);
image.set(x, y, color);
}
}
image
}
}
fn render_worker(
fn sample(&self, w: &World, x: usize, y: usize) -> Color {
if self.samples_per_pixel > 0 {
let color = self
.supersample_rays_for_pixel(x, y, self.samples_per_pixel)
.iter()
.map(|ray| w.color_at(&ray))
.fold(BLACK, |acc, c| acc + c);
color / self.samples_per_pixel as Float
} else {
let ray = self.ray_for_pixel(x, y);
w.color_at(&ray)
}
}
}
fn render_worker_task(
c: &Camera,
w: &World,
input_chan: Arc<Mutex<Receiver<Request>>>,
@ -381,8 +390,7 @@ fn render_worker(
Request::Line { width, y } => {
let mut pixels = Canvas::new(width, 1, BLACK);
for x in 0..width {
let ray = c.ray_for_pixel(x, y);
let color = w.color_at(&ray);
let color = c.sample(w, x, y);
pixels.set(x, 0, color);
}
output_chan