1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use crate::{
    Ray, ray,
    Vec3, cross, normalize
};



/// This struct allows to position viewer in the scene.
pub struct Camera {
    // Camera's position
    position: Vec3,
    // Lower left corner of the canvas
    corner: Vec3,
    // Horizontal scale
    horizontal: Vec3,
    // Vertical scale
    vertical: Vec3
}

impl Camera {
    /// Camera's constructor.
    ///
    /// * `look_from` - Camera's position.
    /// * `look_at` - The point camera is focusing on.
    /// * `up` - `Vec3` that describes "up" direction in the world. Generally (0, 1, 0).
    /// * `fov` - Vertical field of view in degrees.
    /// * `aspect_ratio` - Aspect ratio of image's dimensions: `width / height`.
    pub fn new(look_from: Vec3, look_at: Vec3, up: Vec3, fov: f32, aspect_ratio: f32) -> Camera {
        let half_height = (fov.to_radians() / 2f32).tan();
        let half_width = aspect_ratio * half_height;

        let w = normalize!(look_from - look_at);
        let u = normalize!(cross!(up, w));
        let v = cross!(w, u);

        Camera {
            position: look_from,
            corner: look_from - half_width * u - half_height * v - w,
            horizontal: 2f32 * half_width * u,
            vertical: 2f32 * half_height * v
        }
    }

    /// Emits a Ray for given pixel on virtual camera's canvas.
    ///
    /// * `s` - Horizontal coordinate on canvas. Must be a value in range `[0; 1]`.
    /// * `t` - Vertical coordinate on canvas. Must be a value in range `[0; 1]`.
    pub fn ray(&self, s: f32, t: f32) -> Ray {
        ray!(self.position, self.corner + s * self.horizontal + t * self.vertical - self.position)
    }
}