Skip to main content

wgpu_3dgs_viewer/
camera.rs

1use std::ops::Range;
2
3use glam::*;
4
5/// A camera trait.
6///
7/// This exists to allow for different camera implementations.
8pub trait CameraTrait {
9    /// Get the view matrix.
10    fn view(&self) -> Mat4;
11
12    /// Get the projection matrix.
13    fn projection(&self, aspect_ratio: f32) -> Mat4;
14}
15
16/// A camera.
17#[derive(Debug, Clone)]
18pub struct Camera {
19    /// The position of the camera.
20    pub pos: Vec3,
21    /// The z range of the camera.
22    pub z: Range<f32>,
23    /// The vertical FOV.
24    pub vertical_fov: f32,
25    /// The pitch.
26    pub pitch: f32,
27    /// The yaw.
28    pub yaw: f32,
29}
30
31impl Camera {
32    /// Up direction.
33    pub const UP: Vec3 = Vec3::Y;
34
35    /// The pitch limit.
36    pub const PITCH_LIMIT: Range<f32> =
37        -std::f32::consts::FRAC_PI_2 + 1e-6..std::f32::consts::FRAC_PI_2 - 1e-6;
38
39    /// Create a new camera.
40    pub fn new(z: Range<f32>, vertical_fov: f32) -> Self {
41        Self {
42            pos: Vec3::ZERO,
43            z,
44            vertical_fov,
45            pitch: 0.0,
46            yaw: 0.0,
47        }
48    }
49
50    /// Move the camera.
51    pub fn move_by(&mut self, forward: f32, right: f32) {
52        self.pos += self.get_forward() * forward + self.get_right() * right;
53    }
54
55    /// Move the camera forward.
56    pub fn move_up(&mut self, up: f32) {
57        self.pos += Self::UP * up;
58    }
59
60    /// Apply pitch.
61    pub fn pitch_by(&mut self, delta: f32) {
62        self.pitch = (self.pitch + delta).clamp(Self::PITCH_LIMIT.start, Self::PITCH_LIMIT.end);
63    }
64
65    /// Apply yaw.
66    pub fn yaw_by(&mut self, delta: f32) {
67        self.yaw = (self.yaw + delta).rem_euclid(2.0 * std::f32::consts::PI);
68    }
69
70    /// Get the forward vector.
71    pub fn get_forward(&self) -> Vec3 {
72        Vec3::new(
73            self.pitch.cos() * self.yaw.sin(),
74            self.pitch.sin(),
75            self.pitch.cos() * self.yaw.cos(),
76        )
77    }
78
79    /// Get the right vector.
80    pub fn get_right(&self) -> Vec3 {
81        self.get_forward().cross(Self::UP).normalize()
82    }
83}
84
85impl CameraTrait for Camera {
86    fn view(&self) -> Mat4 {
87        Mat4::look_to_rh(self.pos, self.get_forward(), Self::UP)
88    }
89
90    fn projection(&self, aspect_ratio: f32) -> Mat4 {
91        Mat4::perspective_rh(self.vertical_fov, aspect_ratio, self.z.start, self.z.end)
92    }
93}