bb_camera/
camera3d.rs

1//! The main module for the 3d camera
2
3use bb_geometry::rotation3d::Rotation3D;
4use bb_geometry::vector3d::Vector3D;
5use std::f64::consts::PI;
6
7pub struct Camera3D {
8    distance_min: f64,
9    distance_max: f64,
10    pos: Vector3D,
11    psi: f64,
12    theta: f64,
13    phi: f64,
14    fov_x: f64,
15    fov_y: f64,
16}
17
18const DEFAULT_FOV_X: f64 = 60.0;
19const DEFAULT_FOV_Y: f64 = 60.0;
20const DEFAULT_POS: Vector3D = Vector3D {
21    x: 0.0,
22    y: 0.0,
23    z: 0.0,
24};
25const DEFAULT_PHI: f64 = 0.0;
26const DEFAULT_THETA: f64 = PI / 2.0;
27const DEFAULT_DISTANCE_MIN: f64 = 0.01;
28const DEFAULT_DISTANCE_MAX: f64 = 100.0;
29
30impl Camera3D {
31    pub fn new() -> Self {
32        Camera3D {
33            distance_min: DEFAULT_DISTANCE_MIN,
34            distance_max: DEFAULT_DISTANCE_MAX,
35            pos: DEFAULT_POS,
36            psi: DEFAULT_PHI,
37            theta: DEFAULT_THETA,
38            phi: DEFAULT_PHI,
39            fov_x: DEFAULT_FOV_X,
40            fov_y: DEFAULT_FOV_Y,
41        }
42    }
43
44    pub fn move_pos(&mut self, delta_v: &Vector3D) {
45        self.pos = self.pos.plus(delta_v);
46    }
47
48    pub fn move_psi(&mut self, delta_psi: f64) {
49        self.psi += delta_psi;
50    }
51
52    pub fn move_theta(&mut self, delta_theta: f64) {
53        self.theta += delta_theta;
54    }
55
56    pub fn move_phi(&mut self, delta_phi: f64) {
57        self.phi += delta_phi;
58    }
59
60    pub fn adjust_fov(&mut self, delta_fov_x: f64, delta_fov_y: f64) {
61        self.fov_x += delta_fov_x;
62        self.fov_y += delta_fov_y;
63    }
64
65    pub fn rotation_matrix(&self) -> Rotation3D {
66        Rotation3D::from_euler_angles(self.psi, self.theta, self.phi)
67    }
68
69    pub fn position(&self) -> &Vector3D {
70        &self.pos
71    }
72
73    pub fn theta(&self) -> f64 {
74        self.theta
75    }
76
77    pub fn phi(&self) -> f64 {
78        self.phi
79    }
80
81    pub fn psi(&self) -> f64 {
82        self.psi
83    }
84
85    pub fn fov_x(&self) -> f64 {
86        self.fov_x
87    }
88
89    pub fn fov_y(&self) -> f64 {
90        self.fov_y
91    }
92
93    pub fn distance_min(&self) -> f64 {
94        self.distance_min
95    }
96
97    pub fn distance_max(&self) -> f64 {
98        self.distance_max
99    }
100
101    pub fn projection_matrix(&self) -> [[f32; 4]; 4] {
102        let aspect_ratio = 800.0 / 600.0;
103        let fov_y = self.fov_y.to_radians() as f32;
104        let near = self.distance_min as f32;
105        let far = self.distance_max as f32;
106
107        let f = 1.0 / (fov_y / 2.0).tan();
108
109       [
110            [f / aspect_ratio, 0.0, 0.0, 0.0],
111            [0.0, f, 0.0, 0.0],
112            [0.0, 0.0, (far + near) / (near - far), -1.0],
113            [0.0, 0.0, (2.0 * far * near) / (near - far), 0.0],
114        ]
115    }
116
117    pub fn view_matrix(&self) -> [[f32; 4]; 4] {
118        let rot = self.rotation_matrix().components();
119        let pos = self.rotation_matrix().inverse().act_on(&self.pos).revert().components();
120        [
121            [rot[0][0] as f32, rot[1][0] as f32, rot[2][0] as f32, pos[0] as f32],
122            [rot[0][1] as f32, rot[1][1] as f32, rot[2][1] as f32, pos[1] as f32],
123            [rot[0][2] as f32, rot[1][2] as f32, rot[2][2] as f32, pos[2] as f32],
124            [0.0, 0.0, 0.0, 1.0]
125        ]
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    #[test]
133    fn test_references() {
134        // given
135        let camera = Camera3D::new();
136
137        // when
138        let mut x = camera.psi();
139        x += 0.5;
140
141        // then
142        assert_eq!(x, 0.5);
143        assert_eq!(camera.psi(), 0.0);
144    }
145}