common/
camera.rs

1use crate::vec3::{Point3, Vec3, cross, unit_vector, random_in_unit_disk};
2use crate::ray::Ray;
3use crate::utils::degrees_to_radians;
4
5/// A positionable camera with thin-lens depth of field.
6pub struct Camera {
7    origin: Point3,
8    lower_left_corner: Point3,
9    horizontal: Vec3,
10    vertical: Vec3,
11    u: Vec3,
12    v: Vec3,
13    lens_radius: f64,
14}
15
16impl Camera {
17    /// `lookfrom`: camera origin, `lookat`: point the camera looks at, `vup`: up-direction vector.
18    /// `vfov`: vertical field of view (degrees), `aspect_ratio`: width/height ratio.
19    /// `aperture`: lens aperture diameter (0.0 = pinhole), `focus_dist`: focus distance.
20    pub fn new(
21        lookfrom: Point3,
22        lookat: Point3,
23        vup: Vec3,
24        vfov: f64,
25        aspect_ratio: f64,
26        aperture: f64,
27        focus_dist: f64,
28    ) -> Self {
29        let theta = degrees_to_radians(vfov);
30        let h = (theta / 2.0).tan();
31        let viewport_height = 2.0 * h;
32        let viewport_width = aspect_ratio * viewport_height;
33
34        let w = unit_vector(lookfrom - lookat);
35        let u = unit_vector(cross(vup, w));
36        let v = cross(w, u);
37
38        let origin = lookfrom;
39        let horizontal = focus_dist * viewport_width * u;
40        let vertical = focus_dist * viewport_height * v;
41        let lower_left_corner = origin - horizontal / 2.0 - vertical / 2.0 - focus_dist * w;
42        let lens_radius = aperture / 2.0;
43
44        Camera { origin, lower_left_corner, horizontal, vertical, u, v, lens_radius }
45    }
46
47    /// Returns a ray for the given `(s, t)` viewport coordinates in \[0, 1\].
48    pub fn get_ray(&self, s: f64, t: f64) -> Ray {
49        let rd = self.lens_radius * random_in_unit_disk();
50        let offset = self.u * rd.x() + self.v * rd.y();
51        Ray::new(
52            self.origin + offset,
53            self.lower_left_corner + s * self.horizontal + t * self.vertical - self.origin - offset,
54        )
55    }
56}