Skip to main content

optic_render/util/transform/
transcam.rs

1use optic_core::{CamProj, ClipDist, Size2D};
2use cgmath::*;
3
4/// Camera transform state with pre-computed view and projection matrices.
5///
6/// Holds position, Euler rotation, FOV, clip distances, viewport size, and
7/// projection type. Call [`calc_matrices`](CamTransform::calc_matrices) to
8/// recompute the view, perspective, and orthographic matrices after mutating
9/// any field.
10#[derive(Clone, Debug)]
11pub struct CamTransform {
12    pub pos: Vector3<f32>,
13    pub rot: Vector3<f32>,
14    pub fov: f32,
15    pub clip: ClipDist,
16    pub size: Size2D,
17    pub proj: CamProj,
18    pub view_matrix: Matrix4<f32>,
19    pub ortho_scale: f32,
20    pub front: Vector3<f32>,
21    pub persp_matrix: Matrix4<f32>,
22    pub ortho_matrix: Matrix4<f32>,
23}
24
25impl CamTransform {
26    /// Recalculates view, perspective, and orthographic matrices.
27    ///
28    /// Also updates the `front` direction vector used for fly-through movement.
29    pub fn calc_matrices(&mut self) {
30        let aspect = self.size.aspect_ratio();
31
32        // View matrix
33        let pitch = Rad::from(Deg(self.rot.x));
34        let yaw = Rad::from(Deg(self.rot.y));
35        self.front = vec3(
36            yaw.cos() * pitch.cos(),
37            pitch.sin(),
38            yaw.sin() * pitch.cos(),
39        )
40        .normalize();
41
42        let target = self.pos + self.front;
43        let view = Matrix4::<f32>::look_at_rh(Point3::from_vec(self.pos), Point3::from_vec(target), Vector3::unit_y());
44        self.view_matrix = view;
45
46        // Projection matrices
47        self.persp_matrix = perspective(Rad::from(Deg(self.fov)), aspect, self.clip.near, self.clip.far);
48        self.ortho_matrix = ortho(
49            -self.ortho_scale * aspect,
50            self.ortho_scale * aspect,
51            -self.ortho_scale,
52            self.ortho_scale,
53            self.clip.near,
54            self.clip.far,
55        );
56    }
57
58    /// Returns the view matrix (world-to-camera).
59    pub fn view_matrix(&self) -> Matrix4<f32> {
60        self.view_matrix
61    }
62
63    /// Returns the active projection matrix based on [`proj`](CamTransform::proj).
64    pub fn proj_matrix(&self) -> Matrix4<f32> {
65        match self.proj {
66            CamProj::Persp => self.persp_matrix,
67            CamProj::Ortho => self.ortho_matrix,
68        }
69    }
70}