wgpu_playground/projection.rs
1//! Projection matrices that are intended to be used when the base coordinate system (i.e. the one used by the application code)
2//! is right-handed with the the x-axis pointing right, y-axis pointing *up*, and z-axis pointing *out of the screen*.
3
4/// Orthographic projection matrix.
5///
6/// This matrix is meant to be used when the source coordinate space is right-handed and y-up
7/// (the standard computer graphics coordinate space)and the destination space is left-handed
8/// and y-up, with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
9#[inline]
10pub fn orthographic(
11 left: f32,
12 right: f32,
13 bottom: f32,
14 top: f32,
15 near: f32,
16 far: f32,
17) -> [[f32; 4]; 4] {
18 let rml = right - left;
19 let rpl = right + left;
20 let tmb = top - bottom;
21 let tpb = top + bottom;
22 let fmn = far - near;
23 [
24 [2.0 / rml, 0.0, 0.0, 0.0],
25 [0.0, 2.0 / tmb, 0.0, 0.0],
26 [0.0, 0.0, -1.0 / fmn, 0.0],
27 [-(rpl / rml), -(tpb / tmb), -(near / fmn), 1.0],
28 ]
29}
30
31/// Perspective projection matrix.
32///
33/// * `vertical_fov` should be provided in radians.
34/// * `aspect_ratio` should be the quotient `width / height`.
35///
36/// This matrix is meant to be used when the source coordinate space is right-handed and y-up
37/// (the standard computer graphics coordinate space) and the destination coordinate space is
38/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
39#[inline]
40pub fn perspective(vertical_fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> [[f32; 4]; 4] {
41 let t = (vertical_fov / 2.0).tan();
42 let sy = 1.0 / t;
43 let sx = sy / aspect_ratio;
44 let nmf = z_near - z_far;
45
46 [
47 [sx, 0.0, 0.0, 0.0],
48 [0.0, sy, 0.0, 0.0],
49 [0.0, 0.0, z_far / nmf, -1.0],
50 [0.0, 0.0, z_near * z_far / nmf, 0.0],
51 ]
52}
53
54/// Perspective projection matrix with infinite z-far plane.
55///
56/// This is useful for extremely large scenes where having a far clip plane is extraneous anyway,
57/// as allowing it to approach infinity it eliminates several approximate numerical computations
58/// and so can improve z-fighting behavior.
59///
60/// * `vertical_fov` should be provided in radians.
61/// * `aspect_ratio` should be the quotient `width / height`.
62///
63/// This matrix is meant to be used when the source coordinate space is right-handed and y-up
64/// (the standard computer graphics coordinate space) and the destination coordinate space is
65/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
66#[inline]
67pub fn perspective_infinite_z(vertical_fov: f32, aspect_ratio: f32, z_near: f32) -> [[f32; 4]; 4] {
68 let t = (vertical_fov / 2.0).tan();
69 let sy = 1.0 / t;
70 let sx = sy / aspect_ratio;
71
72 [
73 [sx, 0.0, 0.0, 0.0],
74 [0.0, sy, 0.0, 0.0],
75 [0.0, 0.0, -1.0, -1.0],
76 [0.0, 0.0, -z_near, 0.0],
77 ]
78}
79
80/// Perspective projection matrix with reversed z-axis.
81///
82/// Reversed-Z provides significantly better precision and therefore reduced z-fighting
83/// for most depth situations, especially when a floating-point depth buffer is used. You'll want to use
84/// a reversed depth comparison function and depth clear value when using this projection.
85///
86/// * `vertical_fov` should be provided in radians.
87/// * `aspect_ratio` should be the quotient `width / height`.
88///
89/// This matrix is meant to be used when the source coordinate space is right-handed and y-up
90/// (the standard computer graphics coordinate space) and the destination coordinate space is
91/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
92#[inline]
93pub fn perspective_reversed_z(
94 vertical_fov: f32,
95 aspect_ratio: f32,
96 z_near: f32,
97 z_far: f32,
98) -> [[f32; 4]; 4] {
99 let t = (vertical_fov / 2.0).tan();
100 let sy = 1.0 / t;
101 let sx = sy / aspect_ratio;
102 let nmf = z_near - z_far;
103
104 [
105 [sx, 0.0, 0.0, 0.0],
106 [0.0, sy, 0.0, 0.0],
107 [0.0, 0.0, -z_far / nmf - 1.0, -1.0],
108 [0.0, 0.0, -z_near * z_far / nmf, 0.0],
109 ]
110}
111
112/// Perspective projection matrix with reversed and infinite z-axis.
113///
114/// Reversed-Z provides significantly better precision and therefore reduced z-fighting
115/// for most depth situations, especially when a floating-point depth buffer is used. You'll want to use
116/// a reversed depth comparison function and depth clear value when using this projection.
117///
118/// Infinte-Z is useful for extremely large scenes where having a far clip plane is extraneous anyway,
119/// as allowing it to approach infinity it eliminates several approximate numerical computations
120/// and so can improve z-fighting behavior.
121///
122/// Combining them gives the best of both worlds for large scenes.
123///
124/// * `vertical_fov` should be provided in radians.
125/// * `aspect_ratio` should be the quotient `width / height`.
126///
127/// This matrix is meant to be used when the source coordinate space is right-handed and y-up
128/// (the standard computer graphics coordinate space) and the destination coordinate space is
129/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
130#[inline]
131pub fn perspective_reversed_infinite_z(
132 vertical_fov: f32,
133 aspect_ratio: f32,
134 z_near: f32,
135) -> [[f32; 4]; 4] {
136 let t = (vertical_fov / 2.0).tan();
137 let sy = 1.0 / t;
138 let sx = sy / aspect_ratio;
139
140 [
141 [sx, 0.0, 0.0, 0.0],
142 [0.0, sy, 0.0, 0.0],
143 [0.0, 0.0, 0.0, -1.0],
144 [0.0, 0.0, z_near, 0.0],
145 ]
146}