camera: make supersampling configurable, wire it up in eoc8.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
c4f10126e3
commit
839642b886
@ -22,6 +22,10 @@ use rtchallenge::{
|
|||||||
struct Opt {
|
struct Opt {
|
||||||
#[structopt(long, default_value = "rayon")]
|
#[structopt(long, default_value = "rayon")]
|
||||||
render_strategy: RenderStrategy,
|
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<()> {
|
fn main() -> Result<()> {
|
||||||
@ -38,6 +42,7 @@ fn main() -> Result<()> {
|
|||||||
let up = Tuple::point(0., 1., 0.);
|
let up = Tuple::point(0., 1., 0.);
|
||||||
camera.set_transform(view_transform(from, to, up));
|
camera.set_transform(view_transform(from, to, up));
|
||||||
camera.render_strategy = opt.render_strategy;
|
camera.render_strategy = opt.render_strategy;
|
||||||
|
camera.samples_per_pixel = opt.samples;
|
||||||
|
|
||||||
let mut floor = Sphere::default();
|
let mut floor = Sphere::default();
|
||||||
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
|
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
|
||||||
|
|||||||
@ -13,7 +13,12 @@ use serde::Deserialize;
|
|||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use crate::{
|
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)]
|
#[derive(Copy, Clone, StructOpt, Debug, Deserialize)]
|
||||||
@ -41,6 +46,8 @@ pub struct Camera {
|
|||||||
half_width: Float,
|
half_width: Float,
|
||||||
half_height: Float,
|
half_height: Float,
|
||||||
pub render_strategy: RenderStrategy,
|
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 {
|
enum Request {
|
||||||
@ -94,6 +101,7 @@ impl Camera {
|
|||||||
half_height,
|
half_height,
|
||||||
half_width,
|
half_width,
|
||||||
render_strategy: RenderStrategy::Rayon,
|
render_strategy: RenderStrategy::Rayon,
|
||||||
|
samples_per_pixel: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn hsize(&self) -> usize {
|
pub fn hsize(&self) -> usize {
|
||||||
@ -275,7 +283,7 @@ impl Camera {
|
|||||||
let pixel_resp_tx = pixel_resp_tx.clone();
|
let pixel_resp_tx = pixel_resp_tx.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
core_affinity::set_for_current(id);
|
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<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -322,19 +330,8 @@ impl Camera {
|
|||||||
(0..self.vsize).into_par_iter().for_each(|y| {
|
(0..self.vsize).into_par_iter().for_each(|y| {
|
||||||
let mut row_image = Canvas::new(self.hsize, 1, BLACK);
|
let mut row_image = Canvas::new(self.hsize, 1, BLACK);
|
||||||
for x in 0..self.hsize {
|
for x in 0..self.hsize {
|
||||||
const SAMPLES: usize = 0;
|
let color = self.sample(w, x, y);
|
||||||
if SAMPLES > 0 {
|
row_image.set(x, 0, color);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// TODO(wathiede): create a row based setter for memcpying the row as a whole.
|
// 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");
|
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);
|
let mut image = Canvas::new(self.hsize, self.vsize, BLACK);
|
||||||
for y in 0..self.vsize {
|
for y in 0..self.vsize {
|
||||||
for x in 0..self.hsize {
|
for x in 0..self.hsize {
|
||||||
let ray = self.ray_for_pixel(x, y);
|
let color = self.sample(w, x, y);
|
||||||
let color = w.color_at(&ray);
|
|
||||||
image.set(x, y, color);
|
image.set(x, y, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
image
|
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,
|
c: &Camera,
|
||||||
w: &World,
|
w: &World,
|
||||||
input_chan: Arc<Mutex<Receiver<Request>>>,
|
input_chan: Arc<Mutex<Receiver<Request>>>,
|
||||||
@ -381,8 +390,7 @@ fn render_worker(
|
|||||||
Request::Line { width, y } => {
|
Request::Line { width, y } => {
|
||||||
let mut pixels = Canvas::new(width, 1, BLACK);
|
let mut pixels = Canvas::new(width, 1, BLACK);
|
||||||
for x in 0..width {
|
for x in 0..width {
|
||||||
let ray = c.ray_for_pixel(x, y);
|
let color = c.sample(w, x, y);
|
||||||
let color = w.color_at(&ray);
|
|
||||||
pixels.set(x, 0, color);
|
pixels.set(x, 0, color);
|
||||||
}
|
}
|
||||||
output_chan
|
output_chan
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user