1use crate::vec3::{Point3, Vec3, cross, unit_vector, random_in_unit_disk};
2use crate::ray::Ray;
3use crate::utils::degrees_to_radians;
4
5pub 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 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 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}