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 {
|
pub struct Camera {
|
||||||
hsize: usize,
|
hsize: usize,
|
||||||
vsize: usize,
|
vsize: usize,
|
||||||
field_of_view: f32,
|
field_of_view: f32,
|
||||||
transform: Matrix4x4,
|
pub transform: Matrix4x4,
|
||||||
pixel_size: f32,
|
pixel_size: f32,
|
||||||
half_width: f32,
|
half_width: f32,
|
||||||
half_height: f32,
|
half_height: f32,
|
||||||
@ -70,4 +70,55 @@ impl Camera {
|
|||||||
pub fn pixel_size(&self) -> f32 {
|
pub fn pixel_size(&self) -> f32 {
|
||||||
self.pixel_size
|
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