renderling/camera/
shader.rs1use crabslab::SlabItem;
4use glam::{Mat4, Vec2, Vec3, Vec4};
5
6use crate::{bvol::Frustum, math::IsVector};
7
8#[derive(Default, Clone, Copy, PartialEq, SlabItem, core::fmt::Debug)]
14pub struct CameraDescriptor {
15 projection: Mat4,
16 view: Mat4,
17 position: Vec3,
18 frustum: Frustum,
19 z_near_point: Vec3,
21 z_far_point: Vec3,
23}
24
25impl CameraDescriptor {
26 pub fn new(projection: Mat4, view: Mat4) -> Self {
27 CameraDescriptor::default().with_projection_and_view(projection, view)
28 }
29
30 pub fn default_perspective(width: f32, height: f32) -> Self {
31 let (projection, view) = super::default_perspective(width, height);
32 CameraDescriptor::new(projection, view)
33 }
34
35 pub fn default_ortho2d(width: f32, height: f32) -> Self {
36 let (projection, view) = super::default_ortho2d(width, height);
37 CameraDescriptor::new(projection, view)
38 }
39
40 pub fn projection(&self) -> Mat4 {
41 self.projection
42 }
43
44 pub fn set_projection_and_view(&mut self, projection: Mat4, view: Mat4) {
55 #[cfg(cpu)]
62 {
63 let z_coeff = projection.z_axis.z;
64 if z_coeff > 0.0 {
65 log::warn!(
66 "Projection matrix has a positive z coefficient ({z_coeff}), indicating \
67 reversed depth mapping. This will cause incorrect depth testing (back faces \
68 drawn over front faces) with the standard CompareFunction::Less. For \
69 orthographic projections, ensure near < far."
70 );
71 }
72 }
73 self.projection = projection;
74 self.view = view;
75 self.position = view.inverse().transform_point3(Vec3::ZERO);
76 let inverse = (projection * view).inverse();
77 self.z_near_point = inverse.project_point3(Vec3::ZERO);
78 self.z_far_point = inverse.project_point3(Vec2::ZERO.extend(1.0));
79 self.frustum = Frustum::from_camera(self);
80 }
81
82 pub fn with_projection_and_view(mut self, projection: Mat4, view: Mat4) -> Self {
83 self.set_projection_and_view(projection, view);
84 self
85 }
86
87 pub fn set_projection(&mut self, projection: Mat4) {
88 self.set_projection_and_view(projection, self.view);
89 }
90
91 pub fn with_projection(mut self, projection: Mat4) -> Self {
92 self.set_projection(projection);
93 self
94 }
95
96 pub fn view(&self) -> Mat4 {
97 self.view
98 }
99
100 pub fn set_view(&mut self, view: Mat4) {
101 self.set_projection_and_view(self.projection, view);
102 }
103
104 pub fn with_view(mut self, view: Mat4) -> Self {
105 self.set_view(view);
106 self
107 }
108
109 pub fn position(&self) -> Vec3 {
110 self.position
111 }
112
113 pub fn frustum(&self) -> Frustum {
114 self.frustum
115 }
116
117 pub fn view_projection(&self) -> Mat4 {
118 self.projection * self.view
119 }
120
121 pub fn near_plane(&self) -> Vec4 {
122 self.frustum.planes[0]
123 }
124
125 pub fn far_plane(&self) -> Vec4 {
126 self.frustum.planes[5]
127 }
128
129 pub fn z_near(&self) -> f32 {
131 self.z_near_point.distance(self.position)
132 }
133
134 pub fn z_far(&self) -> f32 {
135 self.z_far_point.distance(self.position)
136 }
137
138 pub fn depth(&self) -> f32 {
139 (self.z_far() - self.z_near()).abs()
140 }
141
142 pub fn forward(&self) -> Vec3 {
145 (self.z_far_point - self.z_near_point).alt_norm_or_zero()
146 }
147
148 pub fn frustum_near_point(&self) -> Vec3 {
149 self.forward() * self.z_near()
150 }
151
152 pub fn frustum_far_point(&self) -> Vec3 {
153 self.forward() * self.z_far()
154 }
155}