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",
|
||||
"criterion",
|
||||
"png",
|
||||
"rayon",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
||||
@ -10,9 +10,13 @@ edition = "2018"
|
||||
anyhow = "1.0.41"
|
||||
criterion = "0.3.4"
|
||||
png = "0.16.8"
|
||||
rayon = "1.5.1"
|
||||
thiserror = "1.0.25"
|
||||
|
||||
|
||||
[[bench]]
|
||||
name = "matrices"
|
||||
harness = false
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
@ -25,7 +25,7 @@ fn main() -> Result<()> {
|
||||
let from = Tuple::point(0., 1.5, -5.);
|
||||
let to = 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();
|
||||
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};
|
||||
|
||||
pub struct Camera {
|
||||
hsize: usize,
|
||||
vsize: usize,
|
||||
field_of_view: f32,
|
||||
pub transform: Matrix4x4,
|
||||
transform: Matrix4x4,
|
||||
inverse_transform: Matrix4x4,
|
||||
pixel_size: f32,
|
||||
half_width: f32,
|
||||
half_height: f32,
|
||||
@ -50,6 +55,7 @@ impl Camera {
|
||||
vsize,
|
||||
field_of_view,
|
||||
transform: Matrix4x4::identity(),
|
||||
inverse_transform: Matrix4x4::identity(),
|
||||
pixel_size,
|
||||
half_height,
|
||||
half_width,
|
||||
@ -67,6 +73,10 @@ impl Camera {
|
||||
pub fn transform(&self) -> Matrix4x4 {
|
||||
self.transform
|
||||
}
|
||||
pub fn set_transform(&mut self, t: Matrix4x4) {
|
||||
self.transform = t;
|
||||
self.inverse_transform = t.inverse();
|
||||
}
|
||||
pub fn pixel_size(&self) -> f32 {
|
||||
self.pixel_size
|
||||
}
|
||||
@ -94,7 +104,7 @@ impl Camera {
|
||||
///
|
||||
/// // Constructing a ray when the camera is transformed.
|
||||
/// 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);
|
||||
/// assert_eq!(r.origin, Tuple::point(0., 2., -5.));
|
||||
/// assert_eq!(
|
||||
@ -115,8 +125,8 @@ impl Camera {
|
||||
// Using the camera matrix, transofmrm the canvas point and the origin,
|
||||
// and then compute the ray's direction vector.
|
||||
// (Remember that the canves is at z>=-1).
|
||||
let pixel = self.transform.inverse() * Tuple::point(world_x, world_y, -1.);
|
||||
let origin = self.transform.inverse() * Tuple::point(0., 0., 0.);
|
||||
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)
|
||||
@ -141,11 +151,37 @@ impl Camera {
|
||||
/// let from = Tuple::point(0., 0., -5.);
|
||||
/// let to = Tuple::point(0., 0., 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);
|
||||
/// assert_eq!(image.get(5, 5), Color::new(0.38066, 0.47583, 0.2855));
|
||||
/// ```
|
||||
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);
|
||||
for y in 0..self.vsize {
|
||||
for x in 0..self.hsize {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user