camera: moving another doctest to unit
This commit is contained in:
parent
e3d8988658
commit
3838efd134
@ -118,27 +118,6 @@ enum Response {
|
|||||||
impl Camera {
|
impl Camera {
|
||||||
/// Create a camera with a canvas of pixel hsize (height) and vsize (width)
|
/// Create a camera with a canvas of pixel hsize (height) and vsize (width)
|
||||||
/// with the given field of view (in radians).
|
/// with the given field of view (in radians).
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use rtchallenge::{camera::Camera, float::consts::PI, matrices::Matrix4x4, EPSILON};
|
|
||||||
///
|
|
||||||
/// let hsize = 160;
|
|
||||||
/// let vsize = 120;
|
|
||||||
/// let field_of_view = PI / 2.;
|
|
||||||
/// let c = Camera::new(hsize, vsize, field_of_view);
|
|
||||||
/// assert_eq!(c.hsize(), 160);
|
|
||||||
/// assert_eq!(c.vsize(), 120);
|
|
||||||
/// assert_eq!(c.transform(), Matrix4x4::identity());
|
|
||||||
///
|
|
||||||
/// // Pixel size for a horizontal canvas.
|
|
||||||
/// let c = Camera::new(200, 150, PI / 2.);
|
|
||||||
/// assert!((c.pixel_size() - 0.010).abs() < EPSILON);
|
|
||||||
///
|
|
||||||
/// // Pixel size for a horizontal canvas.
|
|
||||||
/// let c = Camera::new(150, 200, PI / 2.);
|
|
||||||
/// assert!((c.pixel_size() - 0.010).abs() < EPSILON);
|
|
||||||
/// ```
|
|
||||||
pub fn new(hsize: usize, vsize: usize, field_of_view: Float) -> Camera {
|
pub fn new(hsize: usize, vsize: usize, field_of_view: Float) -> Camera {
|
||||||
let half_view = (field_of_view / 2.).tan();
|
let half_view = (field_of_view / 2.).tan();
|
||||||
let aspect = hsize as Float / vsize as Float;
|
let aspect = hsize as Float / vsize as Float;
|
||||||
@ -208,35 +187,6 @@ impl Camera {
|
|||||||
|
|
||||||
/// Calculate ray that starts at the camera and passes through the (x,y)
|
/// Calculate ray that starts at the camera and passes through the (x,y)
|
||||||
/// pixel on the canvas.
|
/// pixel on the canvas.
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use rtchallenge::{
|
|
||||||
/// camera::Camera, float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// // 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.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!(
|
|
||||||
/// r.direction,
|
|
||||||
/// Tuple::vector((2. as Float).sqrt() / 2., 0., -(2. as Float).sqrt() / 2.)
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray {
|
pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray {
|
||||||
// The offset from the edge of the canvas to the pixel's corner.
|
// The offset from the edge of the canvas to the pixel's corner.
|
||||||
let xoffset = (px as Float + 0.5) * self.pixel_size;
|
let xoffset = (px as Float + 0.5) * self.pixel_size;
|
||||||
@ -258,26 +208,6 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Use camera to render an image of the given world.
|
/// Use camera to render an image of the given world.
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use rtchallenge::{
|
|
||||||
/// camera::Camera,
|
|
||||||
/// float::consts::PI,
|
|
||||||
/// transformations::view_transform,
|
|
||||||
/// tuples::{Color, Tuple},
|
|
||||||
/// world::World,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// // Rendering a world with a camera.
|
|
||||||
/// let w = World::test_world();
|
|
||||||
/// let mut c = Camera::new(11, 11, PI / 2.);
|
|
||||||
/// let from = Tuple::point(0., 0., -5.);
|
|
||||||
/// let to = Tuple::point(0., 0., 0.);
|
|
||||||
/// let up = Tuple::vector(0., 1., 0.);
|
|
||||||
/// 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 {
|
pub fn render(&self, w: &World) -> Canvas {
|
||||||
use RenderStrategy::*;
|
use RenderStrategy::*;
|
||||||
|
|
||||||
@ -437,3 +367,70 @@ fn render_worker_task(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
camera::Camera,
|
||||||
|
float::consts::PI,
|
||||||
|
matrices::Matrix4x4,
|
||||||
|
transformations::view_transform,
|
||||||
|
tuples::{point, vector},
|
||||||
|
world::World,
|
||||||
|
Float, EPSILON,
|
||||||
|
};
|
||||||
|
#[test]
|
||||||
|
fn new() {
|
||||||
|
let hsize = 160;
|
||||||
|
let vsize = 120;
|
||||||
|
let field_of_view = PI / 2.;
|
||||||
|
let c = Camera::new(hsize, vsize, field_of_view);
|
||||||
|
assert_eq!(c.hsize(), 160);
|
||||||
|
assert_eq!(c.vsize(), 120);
|
||||||
|
assert_eq!(c.transform(), Matrix4x4::identity());
|
||||||
|
|
||||||
|
// Pixel size for a horizontal canvas.
|
||||||
|
let c = Camera::new(200, 150, PI / 2.);
|
||||||
|
assert!((c.pixel_size() - 0.010).abs() < EPSILON);
|
||||||
|
|
||||||
|
// Pixel size for a horizontal canvas.
|
||||||
|
let c = Camera::new(150, 200, PI / 2.);
|
||||||
|
assert!((c.pixel_size() - 0.010).abs() < EPSILON);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn ray_for_pixel() {
|
||||||
|
// 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, point(0., 0., 0.));
|
||||||
|
assert_eq!(r.direction, 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, point(0., 0., 0.));
|
||||||
|
assert_eq!(r.direction, 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.set_transform(Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.));
|
||||||
|
let r = c.ray_for_pixel(100, 50);
|
||||||
|
assert_eq!(r.origin, point(0., 2., -5.));
|
||||||
|
assert_eq!(
|
||||||
|
r.direction,
|
||||||
|
vector((2. as Float).sqrt() / 2., 0., -(2. as Float).sqrt() / 2.)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn render() {
|
||||||
|
// Rendering a world with a camera.
|
||||||
|
let w = World::test_world();
|
||||||
|
let mut c = Camera::new(11, 11, PI / 2.);
|
||||||
|
let from = point(0., 0., -5.);
|
||||||
|
let to = point(0., 0., 0.);
|
||||||
|
let up = vector(0., 1., 0.);
|
||||||
|
c.set_transform(view_transform(from, to, up));
|
||||||
|
let image = c.render(&w);
|
||||||
|
assert_eq!(image.get(5, 5), [0.38066, 0.47583, 0.2855].into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user