1use rand::rngs::ThreadRng;
2
3use crate::{
4 math::{Point3, Ray, Vector3},
5 utils::random_in_unit_disk,
6};
7
8pub struct Camera {
9 origin: Point3,
10 lower_left_corner: Point3,
11 horizontal: Vector3,
12 vertical: Vector3,
13 u: Vector3,
14 v: Vector3,
15 lens_radius: f64,
16 pub aspect_ratio: f64,
17}
18
19impl Camera {
20 pub fn new(
21 lookfrom: Point3,
22 lookat: Point3,
23 vup: Vector3,
24 vfov: f64,
25 aspect_ratio: f64,
26 apeture: f64,
27 focus_dist: f64,
28 ) -> Self {
29 let viewport_height = 2.0 * (vfov.to_radians() / 2.0).tan();
30 let viewport_width = aspect_ratio * viewport_height;
31
32 let w = (lookfrom - lookat).unit_vector();
33 let u = Vector3::cross(&vup, &w).unit_vector();
34 let v = Vector3::cross(&w, &u);
35
36 let origin = lookfrom;
37 let horizontal = focus_dist * viewport_width * u;
38 let vertical = focus_dist * viewport_height * v;
39
40 let lens_radius = apeture / 2.0;
41
42 Camera {
43 origin,
44 horizontal,
45 vertical,
46 lower_left_corner: origin - horizontal / 2.0 - vertical / 2.0 - focus_dist * w,
47 aspect_ratio,
48 u,
49 v,
50 lens_radius,
51 }
52 }
53
54 pub fn ray(&self, s: f64, t: f64, rng: &mut ThreadRng) -> Ray {
55 let focus_disk = self.lens_radius * random_in_unit_disk(rng);
56 let offset = self.u * focus_disk.x() + self.v * focus_disk.y();
57
58 Ray::new(
59 self.origin + offset,
60 self.lower_left_corner + s * self.horizontal + t * self.vertical - self.origin - offset,
61 )
62 }
63}