renderling/
camera.rs

1//! Camera projection, view and utilities.
2use glam::{Mat4, Vec3};
3
4#[cfg(cpu)]
5mod cpu;
6#[cfg(cpu)]
7pub use cpu::*;
8
9pub mod shader;
10
11/// Returns the projection and view matrices for a camera with default
12/// perspective.
13///
14/// The default projection and view matrices are defined as:
15///
16/// ```rust
17/// use glam::*;
18///
19/// let width = 800.0;
20/// let height = 600.0;
21/// let aspect = width / height;
22/// let fovy = core::f32::consts::PI / 4.0;
23/// let znear = 0.1;
24/// let zfar = 100.0;
25/// let projection = Mat4::perspective_rh(fovy, aspect, znear, zfar);
26/// let eye = Vec3::new(0.0, 12.0, 20.0);
27/// let target = Vec3::ZERO;
28/// let up = Vec3::Y;
29/// let view = Mat4::look_at_rh(eye, target, up);
30/// assert_eq!(renderling::camera::default_perspective(width, height), (projection, view));
31/// ```
32pub fn default_perspective(width: f32, height: f32) -> (Mat4, Mat4) {
33    let projection = perspective(width, height);
34    let eye = Vec3::new(0.0, 12.0, 20.0);
35    let target = Vec3::ZERO;
36    let up = Vec3::Y;
37    let view = Mat4::look_at_rh(eye, target, up);
38    (projection, view)
39}
40
41pub fn perspective(width: f32, height: f32) -> Mat4 {
42    let aspect = width / height;
43    let fovy = core::f32::consts::PI / 4.0;
44    let znear = 0.1;
45    let zfar = 100.0;
46    Mat4::perspective_rh(fovy, aspect, znear, zfar)
47}
48
49pub fn ortho(width: f32, height: f32) -> Mat4 {
50    let left = 0.0;
51    let right = width;
52    let bottom = height;
53    let top = 0.0;
54    let near = -1.0;
55    let far = 1.0;
56    Mat4::orthographic_rh(left, right, bottom, top, near, far)
57}
58
59pub fn look_at(eye: impl Into<Vec3>, target: impl Into<Vec3>, up: impl Into<Vec3>) -> Mat4 {
60    Mat4::look_at_rh(eye.into(), target.into(), up.into())
61}
62
63/// Creates a typical 2d orthographic projection with +Y extending downward
64/// and the +Z axis coming out towards the viewer.
65pub fn default_ortho2d(width: f32, height: f32) -> (Mat4, Mat4) {
66    let left = 0.0;
67    let right = width;
68    let bottom = height;
69    let top = 0.0;
70    let near = -1.0;
71    let far = 1.0;
72    let projection = Mat4::orthographic_rh(left, right, bottom, top, near, far);
73    let view = Mat4::IDENTITY;
74    (projection, view)
75}
76
77#[cfg(test)]
78mod tests {
79    use crate::camera::shader::CameraDescriptor;
80
81    use super::*;
82    use glam::Vec3;
83
84    #[test]
85    fn forward() {
86        let eyes = [Vec3::new(0.0, 0.0, 5.0), Vec3::new(250.0, 200.0, 250.0)];
87
88        let expected_forwards = [
89            Vec3::new(0.0, 0.0, -1.0),
90            Vec3::new(-0.6154574, -0.49236593, -0.6154574),
91        ];
92
93        for (eye, expected_forward) in eyes.into_iter().zip(expected_forwards) {
94            let projection = Mat4::perspective_rh(45.0_f32.to_radians(), 800.0 / 600.0, 0.1, 100.0);
95            let view = Mat4::look_at_rh(eye, Vec3::ZERO, Vec3::Y);
96            let camera = CameraDescriptor::new(projection, view);
97
98            let forward = camera.forward();
99            let distance = forward.distance(expected_forward);
100            const THRESHOLD: f32 = 1e-3;
101            assert!(
102                distance < THRESHOLD,
103                "Forward vector is incorrect\n\
104                forward: {forward}\n\
105                expected: {expected_forward}\n\
106                distance: {distance}, threshold: {THRESHOLD}"
107            );
108        }
109    }
110}