nightshade/ecs/camera/components/
perspective.rs1use nalgebra_glm::Mat4;
2
3#[derive(
8 Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize, enum2schema::Schema,
9)]
10pub struct PerspectiveCamera {
11 pub aspect_ratio: Option<f32>,
13 pub y_fov_rad: f32,
15 pub z_far: Option<f32>,
17 pub z_near: f32,
19}
20
21impl Default for PerspectiveCamera {
22 fn default() -> Self {
23 Self {
24 aspect_ratio: None,
25 y_fov_rad: 45.0_f32.to_radians(),
26 z_far: None,
27 z_near: 0.01,
28 }
29 }
30}
31
32impl PerspectiveCamera {
33 pub fn matrix(&self) -> Mat4 {
35 let aspect_ratio = self.aspect_ratio.unwrap_or(16.0 / 9.0);
36 self.matrix_with_aspect(aspect_ratio)
37 }
38
39 pub fn matrix_with_aspect(&self, aspect_ratio: f32) -> Mat4 {
41 match self.z_far {
42 Some(z_far) => reverse_z_perspective(aspect_ratio, self.y_fov_rad, self.z_near, z_far),
43 None => infinite_reverse_z_perspective(aspect_ratio, self.y_fov_rad, self.z_near),
44 }
45 }
46}
47
48fn infinite_reverse_z_perspective(aspect_ratio: f32, y_fov_rad: f32, z_near: f32) -> Mat4 {
49 let f = 1.0 / (y_fov_rad / 2.0).tan();
50 Mat4::new(
51 f / aspect_ratio,
52 0.0,
53 0.0,
54 0.0,
55 0.0,
56 f,
57 0.0,
58 0.0,
59 0.0,
60 0.0,
61 0.0,
62 z_near,
63 0.0,
64 0.0,
65 -1.0,
66 0.0,
67 )
68}
69
70fn reverse_z_perspective(aspect_ratio: f32, y_fov_rad: f32, z_near: f32, z_far: f32) -> Mat4 {
71 let f = 1.0 / (y_fov_rad / 2.0).tan();
72 Mat4::new(
73 f / aspect_ratio,
74 0.0,
75 0.0,
76 0.0,
77 0.0,
78 f,
79 0.0,
80 0.0,
81 0.0,
82 0.0,
83 z_near / (z_far - z_near),
84 z_near * z_far / (z_far - z_near),
85 0.0,
86 0.0,
87 -1.0,
88 0.0,
89 )
90}