camera: cache inverse tranform for huge speed up on ray_for_pixel.
WIP parallel render function.
This commit is contained in:
parent
2395c96e01
commit
538b8ad364
1
rtchallenge/Cargo.lock
generated
1
rtchallenge/Cargo.lock
generated
@ -441,6 +441,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"criterion",
|
"criterion",
|
||||||
"png",
|
"png",
|
||||||
|
"rayon",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -10,9 +10,13 @@ edition = "2018"
|
|||||||
anyhow = "1.0.41"
|
anyhow = "1.0.41"
|
||||||
criterion = "0.3.4"
|
criterion = "0.3.4"
|
||||||
png = "0.16.8"
|
png = "0.16.8"
|
||||||
|
rayon = "1.5.1"
|
||||||
thiserror = "1.0.25"
|
thiserror = "1.0.25"
|
||||||
|
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "matrices"
|
name = "matrices"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
@ -25,7 +25,7 @@ fn main() -> Result<()> {
|
|||||||
let from = Tuple::point(0., 1.5, -5.);
|
let from = Tuple::point(0., 1.5, -5.);
|
||||||
let to = Tuple::point(0., 1., 0.);
|
let to = Tuple::point(0., 1., 0.);
|
||||||
let up = Tuple::point(0., 1., 0.);
|
let up = Tuple::point(0., 1., 0.);
|
||||||
camera.transform = view_transform(from, to, up);
|
camera.set_transform(view_transform(from, to, up));
|
||||||
|
|
||||||
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.));
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
use crate::{canvas::Canvas, matrices::Matrix4x4, rays::Ray, tuples::Tuple, world::World, BLACK};
|
use crate::{canvas::Canvas, matrices::Matrix4x4, rays::Ray, tuples::Tuple, world::World, BLACK};
|
||||||
|
|
||||||
pub struct Camera {
|
pub struct Camera {
|
||||||
hsize: usize,
|
hsize: usize,
|
||||||
vsize: usize,
|
vsize: usize,
|
||||||
field_of_view: f32,
|
field_of_view: f32,
|
||||||
pub transform: Matrix4x4,
|
transform: Matrix4x4,
|
||||||
|
inverse_transform: Matrix4x4,
|
||||||
pixel_size: f32,
|
pixel_size: f32,
|
||||||
half_width: f32,
|
half_width: f32,
|
||||||
half_height: f32,
|
half_height: f32,
|
||||||
@ -50,6 +55,7 @@ impl Camera {
|
|||||||
vsize,
|
vsize,
|
||||||
field_of_view,
|
field_of_view,
|
||||||
transform: Matrix4x4::identity(),
|
transform: Matrix4x4::identity(),
|
||||||
|
inverse_transform: Matrix4x4::identity(),
|
||||||
pixel_size,
|
pixel_size,
|
||||||
half_height,
|
half_height,
|
||||||
half_width,
|
half_width,
|
||||||
@ -67,6 +73,10 @@ impl Camera {
|
|||||||
pub fn transform(&self) -> Matrix4x4 {
|
pub fn transform(&self) -> Matrix4x4 {
|
||||||
self.transform
|
self.transform
|
||||||
}
|
}
|
||||||
|
pub fn set_transform(&mut self, t: Matrix4x4) {
|
||||||
|
self.transform = t;
|
||||||
|
self.inverse_transform = t.inverse();
|
||||||
|
}
|
||||||
pub fn pixel_size(&self) -> f32 {
|
pub fn pixel_size(&self) -> f32 {
|
||||||
self.pixel_size
|
self.pixel_size
|
||||||
}
|
}
|
||||||
@ -94,7 +104,7 @@ impl Camera {
|
|||||||
///
|
///
|
||||||
/// // Constructing a ray when the camera is transformed.
|
/// // Constructing a ray when the camera is transformed.
|
||||||
/// let mut c = Camera::new(201, 101, PI / 2.);
|
/// let mut c = Camera::new(201, 101, PI / 2.);
|
||||||
/// c.transform = Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.);
|
/// c.set_transform(Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.));
|
||||||
/// let r = c.ray_for_pixel(100, 50);
|
/// let r = c.ray_for_pixel(100, 50);
|
||||||
/// assert_eq!(r.origin, Tuple::point(0., 2., -5.));
|
/// assert_eq!(r.origin, Tuple::point(0., 2., -5.));
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
@ -115,8 +125,8 @@ impl Camera {
|
|||||||
// Using the camera matrix, transofmrm the canvas point and the origin,
|
// Using the camera matrix, transofmrm the canvas point and the origin,
|
||||||
// and then compute the ray's direction vector.
|
// and then compute the ray's direction vector.
|
||||||
// (Remember that the canves is at z>=-1).
|
// (Remember that the canves is at z>=-1).
|
||||||
let pixel = self.transform.inverse() * Tuple::point(world_x, world_y, -1.);
|
let pixel = self.inverse_transform * Tuple::point(world_x, world_y, -1.);
|
||||||
let origin = self.transform.inverse() * Tuple::point(0., 0., 0.);
|
let origin = self.inverse_transform * Tuple::point(0., 0., 0.);
|
||||||
let direction = (pixel - origin).normalize();
|
let direction = (pixel - origin).normalize();
|
||||||
|
|
||||||
Ray::new(origin, direction)
|
Ray::new(origin, direction)
|
||||||
@ -141,11 +151,37 @@ impl Camera {
|
|||||||
/// let from = Tuple::point(0., 0., -5.);
|
/// let from = Tuple::point(0., 0., -5.);
|
||||||
/// let to = Tuple::point(0., 0., 0.);
|
/// let to = Tuple::point(0., 0., 0.);
|
||||||
/// let up = Tuple::vector(0., 1., 0.);
|
/// let up = Tuple::vector(0., 1., 0.);
|
||||||
/// c.transform = view_transform(from, to, up);
|
/// c.set_transform(view_transform(from, to, up));
|
||||||
/// let image = c.render(&w);
|
/// let image = c.render(&w);
|
||||||
/// assert_eq!(image.get(5, 5), Color::new(0.38066, 0.47583, 0.2855));
|
/// assert_eq!(image.get(5, 5), Color::new(0.38066, 0.47583, 0.2855));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn render(&self, w: &World) -> Canvas {
|
pub fn render(&self, w: &World) -> Canvas {
|
||||||
|
self.render_serial(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn render_parallel(&self, w: &World) -> Canvas {
|
||||||
|
let image_mu = Mutex::new(Canvas::new(self.hsize, self.vsize, BLACK));
|
||||||
|
|
||||||
|
(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);
|
||||||
|
}
|
||||||
|
// 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");
|
||||||
|
for x in 0..self.hsize {
|
||||||
|
image.set(x, y, row_image.get(x, 0));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
image_mu
|
||||||
|
.into_inner()
|
||||||
|
.expect("failed to get image out of mutex")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_serial(&self, w: &World) -> Canvas {
|
||||||
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 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user