Skip to main content

scenix_helpers/
camera_helper.rs

1use scenix_camera::{OrthographicCamera, PerspectiveCamera};
2use scenix_core::Color;
3use scenix_math::{Mat4, Vec3};
4
5use crate::LineGeometry;
6
7/// Camera frustum wireframe helper.
8#[derive(Clone, Copy, Debug, PartialEq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct CameraHelper {
11    /// Camera view-projection matrix.
12    pub view_projection: Mat4,
13    /// Line color.
14    pub color: Color,
15}
16
17impl CameraHelper {
18    /// Creates a helper from a view-projection matrix.
19    #[inline]
20    pub const fn new(view_projection: Mat4, color: Color) -> Self {
21        Self {
22            view_projection,
23            color,
24        }
25    }
26
27    /// Creates a helper from a perspective camera.
28    #[inline]
29    pub fn from_perspective(camera: &PerspectiveCamera, color: Color) -> Self {
30        Self::new(camera.view_projection(), color)
31    }
32
33    /// Creates a helper from an orthographic camera.
34    #[inline]
35    pub fn from_orthographic(camera: &OrthographicCamera, color: Color) -> Self {
36        Self::new(camera.view_projection(), color)
37    }
38
39    /// Generates frustum edge geometry.
40    pub fn to_geometry(&self) -> LineGeometry {
41        let inverse = self.view_projection.inverse().unwrap_or(Mat4::IDENTITY);
42        let ndc = [
43            Vec3::new(-1.0, -1.0, 0.0),
44            Vec3::new(1.0, -1.0, 0.0),
45            Vec3::new(1.0, 1.0, 0.0),
46            Vec3::new(-1.0, 1.0, 0.0),
47            Vec3::new(-1.0, -1.0, 1.0),
48            Vec3::new(1.0, -1.0, 1.0),
49            Vec3::new(1.0, 1.0, 1.0),
50            Vec3::new(-1.0, 1.0, 1.0),
51        ];
52        let mut corners = [Vec3::ZERO; 8];
53        for (out, corner) in corners.iter_mut().zip(ndc) {
54            *out = inverse.mul_vec3(corner);
55        }
56
57        let edges = [
58            (0, 1),
59            (1, 2),
60            (2, 3),
61            (3, 0),
62            (4, 5),
63            (5, 6),
64            (6, 7),
65            (7, 4),
66            (0, 4),
67            (1, 5),
68            (2, 6),
69            (3, 7),
70        ];
71        let mut geometry = LineGeometry::new();
72        for (a, b) in edges {
73            geometry.push_segment(corners[a], corners[b], self.color);
74        }
75        geometry
76    }
77}