Skip to main content

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!(
31///     renderling::camera::default_perspective(width, height),
32///     (projection, view)
33/// );
34/// ```
35pub fn default_perspective(width: f32, height: f32) -> (Mat4, Mat4) {
36    let projection = perspective(width, height);
37    let eye = Vec3::new(0.0, 12.0, 20.0);
38    let target = Vec3::ZERO;
39    let up = Vec3::Y;
40    let view = Mat4::look_at_rh(eye, target, up);
41    (projection, view)
42}
43
44pub fn perspective(width: f32, height: f32) -> Mat4 {
45    let aspect = width / height;
46    let fovy = core::f32::consts::PI / 4.0;
47    let znear = 0.1;
48    let zfar = 100.0;
49    Mat4::perspective_rh(fovy, aspect, znear, zfar)
50}
51
52/// Creates a right-handed orthographic projection matrix.
53///
54/// ## Note
55/// When constructing orthographic projections, `near` must be less than `far`
56/// to ensure correct depth testing. Reversed depth (`near > far`) will cause
57/// back faces to be drawn over front faces, producing incorrect lighting.
58pub fn ortho(width: f32, height: f32) -> Mat4 {
59    let left = 0.0;
60    let right = width;
61    let bottom = height;
62    let top = 0.0;
63    let near = -1.0;
64    let far = 1.0;
65    Mat4::orthographic_rh(left, right, bottom, top, near, far)
66}
67
68pub fn look_at(eye: impl Into<Vec3>, target: impl Into<Vec3>, up: impl Into<Vec3>) -> Mat4 {
69    Mat4::look_at_rh(eye.into(), target.into(), up.into())
70}
71
72/// Creates a typical 2d orthographic projection with +Y extending downward
73/// and the +Z axis coming out towards the viewer.
74///
75/// ## Note
76/// When constructing orthographic projections, `near` must be less than `far`
77/// to ensure correct depth testing. Reversed depth (`near > far`) will cause
78/// back faces to be drawn over front faces, producing incorrect lighting.
79pub fn default_ortho2d(width: f32, height: f32) -> (Mat4, Mat4) {
80    let left = 0.0;
81    let right = width;
82    let bottom = height;
83    let top = 0.0;
84    let near = -1.0;
85    let far = 1.0;
86    let projection = Mat4::orthographic_rh(left, right, bottom, top, near, far);
87    let view = Mat4::IDENTITY;
88    (projection, view)
89}
90
91#[cfg(test)]
92mod tests {
93    use crate::camera::shader::CameraDescriptor;
94
95    use super::*;
96    use glam::Vec3;
97
98    #[test]
99    fn forward() {
100        let eyes = [Vec3::new(0.0, 0.0, 5.0), Vec3::new(250.0, 200.0, 250.0)];
101
102        let expected_forwards = [
103            Vec3::new(0.0, 0.0, -1.0),
104            Vec3::new(-0.6154574, -0.49236593, -0.6154574),
105        ];
106
107        for (eye, expected_forward) in eyes.into_iter().zip(expected_forwards) {
108            let projection = Mat4::perspective_rh(45.0_f32.to_radians(), 800.0 / 600.0, 0.1, 100.0);
109            let view = Mat4::look_at_rh(eye, Vec3::ZERO, Vec3::Y);
110            let camera = CameraDescriptor::new(projection, view);
111
112            let forward = camera.forward();
113            let distance = forward.distance(expected_forward);
114            const THRESHOLD: f32 = 1e-3;
115            assert!(
116                distance < THRESHOLD,
117                "Forward vector is incorrect\nforward: {forward}\nexpected: \
118                 {expected_forward}\ndistance: {distance}, threshold: {THRESHOLD}"
119            );
120        }
121    }
122}