renderling/camera/
shader.rs

1//! [`CameraDescriptor`] and camera shader utilities.
2
3use crabslab::SlabItem;
4use glam::{Mat4, Vec2, Vec3, Vec4};
5
6use crate::{bvol::Frustum, math::IsVector};
7
8/// GPU descriptor of a camera.
9///
10/// Used for transforming the stage during rendering.
11///
12/// Use [`CameraDescriptor::new`] to create a new camera.
13#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
14#[derive(Default, Clone, Copy, PartialEq, SlabItem)]
15pub struct CameraDescriptor {
16    projection: Mat4,
17    view: Mat4,
18    position: Vec3,
19    frustum: Frustum,
20    /// Nearest center point on the frustum
21    z_near_point: Vec3,
22    /// Furthest center point on the frustum
23    z_far_point: Vec3,
24}
25
26impl CameraDescriptor {
27    pub fn new(projection: Mat4, view: Mat4) -> Self {
28        CameraDescriptor::default().with_projection_and_view(projection, view)
29    }
30
31    pub fn default_perspective(width: f32, height: f32) -> Self {
32        let (projection, view) = super::default_perspective(width, height);
33        CameraDescriptor::new(projection, view)
34    }
35
36    pub fn default_ortho2d(width: f32, height: f32) -> Self {
37        let (projection, view) = super::default_ortho2d(width, height);
38        CameraDescriptor::new(projection, view)
39    }
40
41    pub fn projection(&self) -> Mat4 {
42        self.projection
43    }
44
45    pub fn set_projection_and_view(&mut self, projection: Mat4, view: Mat4) {
46        self.projection = projection;
47        self.view = view;
48        self.position = view.inverse().transform_point3(Vec3::ZERO);
49        let inverse = (projection * view).inverse();
50        self.z_near_point = inverse.project_point3(Vec3::ZERO);
51        self.z_far_point = inverse.project_point3(Vec2::ZERO.extend(1.0));
52        self.frustum = Frustum::from_camera(self);
53    }
54
55    pub fn with_projection_and_view(mut self, projection: Mat4, view: Mat4) -> Self {
56        self.set_projection_and_view(projection, view);
57        self
58    }
59
60    pub fn set_projection(&mut self, projection: Mat4) {
61        self.set_projection_and_view(projection, self.view);
62    }
63
64    pub fn with_projection(mut self, projection: Mat4) -> Self {
65        self.set_projection(projection);
66        self
67    }
68
69    pub fn view(&self) -> Mat4 {
70        self.view
71    }
72
73    pub fn set_view(&mut self, view: Mat4) {
74        self.set_projection_and_view(self.projection, view);
75    }
76
77    pub fn with_view(mut self, view: Mat4) -> Self {
78        self.set_view(view);
79        self
80    }
81
82    pub fn position(&self) -> Vec3 {
83        self.position
84    }
85
86    pub fn frustum(&self) -> Frustum {
87        self.frustum
88    }
89
90    pub fn view_projection(&self) -> Mat4 {
91        self.projection * self.view
92    }
93
94    pub fn near_plane(&self) -> Vec4 {
95        self.frustum.planes[0]
96    }
97
98    pub fn far_plane(&self) -> Vec4 {
99        self.frustum.planes[5]
100    }
101
102    /// Returns **roughly** the location of the znear plane.
103    pub fn z_near(&self) -> f32 {
104        self.z_near_point.distance(self.position)
105    }
106
107    pub fn z_far(&self) -> f32 {
108        self.z_far_point.distance(self.position)
109    }
110
111    pub fn depth(&self) -> f32 {
112        (self.z_far() - self.z_near()).abs()
113    }
114
115    /// Returns the normalized forward vector which points in the direction the camera is looking.
116    pub fn forward(&self) -> Vec3 {
117        (self.z_far_point - self.z_near_point).alt_norm_or_zero()
118    }
119
120    pub fn frustum_near_point(&self) -> Vec3 {
121        self.forward() * self.z_near()
122    }
123
124    pub fn frustum_far_point(&self) -> Vec3 {
125        self.forward() * self.z_far()
126    }
127}