camera: implement Camera::ray_for_pixel.
This commit is contained in:
parent
39f7f77b74
commit
5911610064
@ -1,10 +1,10 @@
|
||||
use crate::matrices::Matrix4x4;
|
||||
use crate::{matrices::Matrix4x4, rays::Ray, tuples::Tuple};
|
||||
|
||||
pub struct Camera {
|
||||
hsize: usize,
|
||||
vsize: usize,
|
||||
field_of_view: f32,
|
||||
transform: Matrix4x4,
|
||||
pub transform: Matrix4x4,
|
||||
pixel_size: f32,
|
||||
half_width: f32,
|
||||
half_height: f32,
|
||||
@ -70,4 +70,55 @@ impl Camera {
|
||||
pub fn pixel_size(&self) -> f32 {
|
||||
self.pixel_size
|
||||
}
|
||||
|
||||
/// Calculate ray that starts at the camera and passes through the (x,y)
|
||||
/// pixel on the canvas.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use std::f32::consts::PI;
|
||||
///
|
||||
/// use rtchallenge::{camera::Camera, matrices::Matrix4x4, tuples::Tuple};
|
||||
///
|
||||
/// // Constructing a ray through the center of the canvas.
|
||||
/// let c = Camera::new(201, 101, PI / 2.);
|
||||
/// let r = c.ray_for_pixel(100, 50);
|
||||
/// assert_eq!(r.origin, Tuple::point(0., 0., 0.));
|
||||
/// assert_eq!(r.direction, Tuple::vector(0., 0., -1.));
|
||||
///
|
||||
/// // Constructing a ray through the corner of the canvas.
|
||||
/// let c = Camera::new(201, 101, PI / 2.);
|
||||
/// let r = c.ray_for_pixel(0, 0);
|
||||
/// assert_eq!(r.origin, Tuple::point(0., 0., 0.));
|
||||
/// assert_eq!(r.direction, Tuple::vector(0.66519, 0.33259, -0.66851));
|
||||
///
|
||||
/// // 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.);
|
||||
/// let r = c.ray_for_pixel(100, 50);
|
||||
/// assert_eq!(r.origin, Tuple::point(0., 2., -5.));
|
||||
/// assert_eq!(
|
||||
/// r.direction,
|
||||
/// Tuple::vector(2_f32.sqrt() / 2., 0., -2_f32.sqrt() / 2.)
|
||||
/// );
|
||||
/// ```
|
||||
pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray {
|
||||
// The offset from the edge of the canvas to the pixel's corner.
|
||||
let xoffset = (px as f32 + 0.5) * self.pixel_size;
|
||||
let yoffset = (py as f32 + 0.5) * 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 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 direction = (pixel - origin).normalize();
|
||||
|
||||
Ray::new(origin, direction)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user