ultraviolet/projection/rh_ydown.rs
1//! Projection matrices that are intended to be used when the base coordinate
2//! system (i.e. the one used by the application code) is right-handed, with the
3//! x-axis pointing right, y-axis pointing *down*, and z-axis pointing *into the
4//! screen*.
5
6use crate::mat::*;
7use crate::vec::*;
8
9/// Orthographic projection matrix for use with OpenGL.
10///
11/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
12/// and the destination space is left-handed
13/// and y-up, with Z (depth) clip extending from -1.0 (close) to 1.0 (far).
14#[inline]
15pub fn orthographic_gl(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) -> Mat4 {
16 let rml = right - left;
17 let rpl = right + left;
18 let tmb = top - bottom;
19 let tpb = top + bottom;
20 let fmn = far - near;
21 let fpn = far + near;
22 Mat4::new(
23 Vec4::new(2.0 / rml, 0.0, 0.0, 0.0),
24 Vec4::new(0.0, -2.0 / tmb, 0.0, 0.0),
25 Vec4::new(0.0, 0.0, -2.0 / fmn, 0.0),
26 Vec4::new(-(rpl / rml), -(tpb / tmb), -(fpn / fmn), 1.0),
27 )
28}
29
30/// Orthographic projection matrix for use with OpenGL.
31///
32/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
33/// and the destination space is left-handed
34/// and y-down, with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
35#[inline]
36pub fn orthographic_vk(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) -> Mat4 {
37 let rml = right - left;
38 let rpl = right + left;
39 let tmb = top - bottom;
40 let tpb = top + bottom;
41 let fmn = far - near;
42 Mat4::new(
43 Vec4::new(2.0 / rml, 0.0, 0.0, 0.0),
44 Vec4::new(0.0, 2.0 / tmb, 0.0, 0.0),
45 Vec4::new(0.0, 0.0, -1.0 / fmn, 0.0),
46 Vec4::new(-(rpl / rml), -(tpb / tmb), -(near / fmn), 1.0),
47 )
48}
49
50/// Orthographic projection matrix for use with WebGPU or DirectX.
51///
52/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
53/// and the destination space is left-handed
54/// and y-up, with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
55#[inline]
56pub fn orthographic_wgpu_dx(
57 left: f32,
58 right: f32,
59 bottom: f32,
60 top: f32,
61 near: f32,
62 far: f32,
63) -> Mat4 {
64 let rml = right - left;
65 let rpl = right + left;
66 let tmb = top - bottom;
67 let tpb = top + bottom;
68 let fmn = far - near;
69 Mat4::new(
70 Vec4::new(2.0 / rml, 0.0, 0.0, 0.0),
71 Vec4::new(0.0, -2.0 / tmb, 0.0, 0.0),
72 Vec4::new(0.0, 0.0, -1.0 / fmn, 0.0),
73 Vec4::new(-(rpl / rml), -(tpb / tmb), -(near / fmn), 1.0),
74 )
75}
76
77/// Perspective projection matrix meant to be used with OpenGL.
78///
79/// * `vertical_fov` should be provided in radians.
80/// * `aspect_ratio` should be the quotient `width / height`.
81///
82/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
83/// (the standard computer graphics coordinate space) and the destination coordinate space is
84/// left-handed and y-up with Z (depth) clip extending from -1.0 (close) to 1.0 (far).
85#[inline]
86pub fn perspective_gl(vertical_fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Mat4 {
87 let t = (vertical_fov / 2.0).tan();
88 let sy = 1.0 / t;
89 let sx = sy / aspect_ratio;
90 let nmf = z_near - z_far;
91
92 Mat4::new(
93 Vec4::new(sx, 0.0, 0.0, 0.0),
94 Vec4::new(0.0, -sy, 0.0, 0.0),
95 Vec4::new(0.0, 0.0, (z_far + z_near) / nmf, -1.0),
96 Vec4::new(0.0, 0.0, 2.0 * z_near * z_far / nmf, 0.0),
97 )
98}
99
100/// Perspective projection matrix meant to be used with WebGPU or DirectX.
101///
102/// * `vertical_fov` should be provided in radians.
103/// * `aspect_ratio` should be the quotient `width / height`.
104///
105/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
106/// (the standard computer graphics coordinate space) and the destination coordinate space is
107/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
108#[inline]
109pub fn perspective_wgpu_dx(vertical_fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Mat4 {
110 let t = (vertical_fov / 2.0).tan();
111 let sy = 1.0 / t;
112 let sx = sy / aspect_ratio;
113 let nmf = z_near - z_far;
114
115 Mat4::new(
116 Vec4::new(sx, 0.0, 0.0, 0.0),
117 Vec4::new(0.0, -sy, 0.0, 0.0),
118 Vec4::new(0.0, 0.0, z_far / nmf, -1.0),
119 Vec4::new(0.0, 0.0, z_near * z_far / nmf, 0.0),
120 )
121}
122
123/// Perspective projection matrix meant to be used with Vulkan.
124///
125/// * `vertical_fov` should be provided in radians.
126/// * `aspect_ratio` should be the quotient `width / height`.
127///
128/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
129/// (the standard computer graphics coordinate space) and the destination coordinate space is
130/// right-handed and y-down with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
131#[inline]
132pub fn perspective_vk(vertical_fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Mat4 {
133 let t = (vertical_fov / 2.0).tan();
134 let sy = 1.0 / t;
135 let sx = sy / aspect_ratio;
136 let nmf = z_near - z_far;
137
138 Mat4::new(
139 Vec4::new(sx, 0.0, 0.0, 0.0),
140 Vec4::new(0.0, sy, 0.0, 0.0),
141 Vec4::new(0.0, 0.0, z_far / nmf, -1.0),
142 Vec4::new(0.0, 0.0, z_near * z_far / nmf, 0.0),
143 )
144}
145
146/// Perspective projection matrix with infinite z-far plane meant to be used with OpenGL.
147///
148/// This is useful for extremely large scenes where having a far clip plane is extraneous anyway,
149/// as allowing it to approach infinity it eliminates several approximate numerical computations
150/// and so can improve z-fighting behavior.
151///
152/// * `vertical_fov` should be provided in radians.
153/// * `aspect_ratio` should be the quotient `width / height`.
154///
155/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
156/// (the standard computer graphics coordinate space) and the destination coordinate space is
157/// left-handed and y-up with Z (depth) clip extending from -1.0 (close) to 1.0 (far).
158#[inline]
159pub fn perspective_infinite_z_gl(vertical_fov: f32, aspect_ratio: f32, z_near: f32) -> Mat4 {
160 let t = (vertical_fov / 2.0).tan();
161 let sy = 1.0 / t;
162 let sx = sy / aspect_ratio;
163
164 Mat4::new(
165 Vec4::new(sx, 0.0, 0.0, 0.0),
166 Vec4::new(0.0, -sy, 0.0, 0.0),
167 Vec4::new(0.0, 0.0, -1.0, -1.0),
168 Vec4::new(0.0, 0.0, -2.0 * z_near, 0.0),
169 )
170}
171
172/// Perspective projection matrix with infinite z-far plane meant to be used with Vulkan.
173///
174/// This is useful for extremely large scenes where having a far clip plane is extraneous anyway,
175/// as allowing it to approach infinity it eliminates several approximate numerical computations
176/// and so can improve z-fighting behavior.
177///
178/// * `vertical_fov` should be provided in radians.
179/// * `aspect_ratio` should be the quotient `width / height`.
180///
181/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
182/// (the standard computer graphics coordinate space) and the destination coordinate space is
183/// right-handed and y-down with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
184#[inline]
185pub fn perspective_infinite_z_vk(vertical_fov: f32, aspect_ratio: f32, z_near: f32) -> Mat4 {
186 let t = (vertical_fov / 2.0).tan();
187 let sy = 1.0 / t;
188 let sx = sy / aspect_ratio;
189
190 Mat4::new(
191 Vec4::new(sx, 0.0, 0.0, 0.0),
192 Vec4::new(0.0, sy, 0.0, 0.0),
193 Vec4::new(0.0, 0.0, -1.0, -1.0),
194 Vec4::new(0.0, 0.0, -z_near, 0.0),
195 )
196}
197
198/// Perspective projection matrix with infinite z-far plane meant to be used with WebGPU or DirectX.
199///
200/// This is useful for extremely large scenes where having a far clip plane is extraneous anyway,
201/// as allowing it to approach infinity it eliminates several approximate numerical computations
202/// and so can improve z-fighting behavior.
203///
204/// * `vertical_fov` should be provided in radians.
205/// * `aspect_ratio` should be the quotient `width / height`.
206///
207/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
208/// (the standard computer graphics coordinate space) and the destination coordinate space is
209/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
210#[inline]
211pub fn perspective_infinite_z_wgpu_dx(vertical_fov: f32, aspect_ratio: f32, z_near: f32) -> Mat4 {
212 let t = (vertical_fov / 2.0).tan();
213 let sy = 1.0 / t;
214 let sx = sy / aspect_ratio;
215
216 Mat4::new(
217 Vec4::new(sx, 0.0, 0.0, 0.0),
218 Vec4::new(0.0, -sy, 0.0, 0.0),
219 Vec4::new(0.0, 0.0, -1.0, -1.0),
220 Vec4::new(0.0, 0.0, -z_near, 0.0),
221 )
222}
223
224/// Perspective projection matrix with reversed z-axis meant to be used with WebGPU, DirectX, or OpenGL.
225///
226/// Reversed-Z provides significantly better precision and therefore reduced z-fighting
227/// for most depth situations, especially when a floating-point depth buffer is used. You'll want to use
228/// a reversed depth comparison function and depth clear value when using this projection.
229///
230/// * `vertical_fov` should be provided in radians.
231/// * `aspect_ratio` should be the quotient `width / height`.
232///
233/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
234/// (the standard computer graphics coordinate space) and the destination coordinate space is
235/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
236///
237/// **Note that in order for this to work properly with OpenGL, you'll need to use the `gl_arb_clip_control` extension
238/// and set the z clip from 0.0 to 1.0 rather than the default -1.0 to 1.0**
239#[inline]
240pub fn perspective_reversed_z_wgpu_dx_gl(
241 vertical_fov: f32,
242 aspect_ratio: f32,
243 z_near: f32,
244 z_far: f32,
245) -> Mat4 {
246 let t = (vertical_fov / 2.0).tan();
247 let sy = 1.0 / t;
248 let sx = sy / aspect_ratio;
249 let nmf = z_near - z_far;
250
251 Mat4::new(
252 Vec4::new(sx, 0.0, 0.0, 0.0),
253 Vec4::new(0.0, -sy, 0.0, 0.0),
254 Vec4::new(0.0, 0.0, -z_far / nmf - 1.0, -1.0),
255 Vec4::new(0.0, 0.0, -z_near * z_far / nmf, 0.0),
256 )
257}
258
259/// Perspective projection matrix with reversed z-axis meant to be used with Vulkan.
260///
261/// Reversed-Z provides significantly better precision and therefore reduced z-fighting
262/// for most depth situations, especially when a floating-point depth buffer is used. You'll want to use
263/// a reversed depth comparison function and depth clear value when using this projection.
264///
265/// * `vertical_fov` should be provided in radians.
266/// * `aspect_ratio` should be the quotient `width / height`.
267///
268/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
269/// (the standard computer graphics coordinate space) and the destination coordinate space is
270/// right-handed and y-down with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
271#[inline]
272pub fn perspective_reversed_z_vk(
273 vertical_fov: f32,
274 aspect_ratio: f32,
275 z_near: f32,
276 z_far: f32,
277) -> Mat4 {
278 let t = (vertical_fov / 2.0).tan();
279 let sy = 1.0 / t;
280 let sx = sy / aspect_ratio;
281 let nmf = z_near - z_far;
282
283 Mat4::new(
284 Vec4::new(sx, 0.0, 0.0, 0.0),
285 Vec4::new(0.0, sy, 0.0, 0.0),
286 Vec4::new(0.0, 0.0, z_far / nmf, -1.0),
287 Vec4::new(0.0, 0.0, -z_near * z_far / nmf, 0.0),
288 )
289}
290
291/// Perspective projection matrix with reversed and infinite z-axis meant to be used with WebGPU, OpenGL, or DirectX.
292///
293/// Reversed-Z provides significantly better precision and therefore reduced z-fighting
294/// for most depth situations, especially when a floating-point depth buffer is used. You'll want to use
295/// a reversed depth comparison function and depth clear value when using this projection.
296///
297/// Infinte-Z is useful for extremely large scenes where having a far clip plane is extraneous anyway,
298/// as allowing it to approach infinity it eliminates several approximate numerical computations
299/// and so can improve z-fighting behavior.
300///
301/// Combining them gives the best of both worlds for large scenes.
302///
303/// * `vertical_fov` should be provided in radians.
304/// * `aspect_ratio` should be the quotient `width / height`.
305///
306/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
307/// (the standard computer graphics coordinate space) and the destination coordinate space is
308/// left-handed and y-up with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
309///
310/// **Note that in order for this to work properly with OpenGL, you'll need to use the `gl_arb_clip_control` extension
311/// and set the z clip from 0.0 to 1.0 rather than the default -1.0 to 1.0**
312#[inline]
313pub fn perspective_reversed_infinite_z_wgpu_dx_gl(
314 vertical_fov: f32,
315 aspect_ratio: f32,
316 z_near: f32,
317) -> Mat4 {
318 let t = (vertical_fov / 2.0).tan();
319 let sy = 1.0 / t;
320 let sx = sy / aspect_ratio;
321
322 Mat4::new(
323 Vec4::new(sx, 0.0, 0.0, 0.0),
324 Vec4::new(0.0, -sy, 0.0, 0.0),
325 Vec4::new(0.0, 0.0, 0.0, -1.0),
326 Vec4::new(0.0, 0.0, z_near, 0.0),
327 )
328}
329
330/// Perspective projection matrix with reversed and infinite z-axis meant to be used with Vulkan.
331///
332/// Reversed-Z provides significantly better precision and therefore reduced z-fighting
333/// for most depth situations, especially when a floating-point depth buffer is used. You'll want to use
334/// a reversed depth comparison function and depth clear value when using this projection.
335///
336/// Infinte-Z is useful for extremely large scenes where having a far clip plane is extraneous anyway,
337/// as allowing it to approach infinity it eliminates several approximate numerical computations
338/// and so can improve z-fighting behavior.
339///
340/// Combining them gives the best of both worlds for large scenes.
341///
342/// * `vertical_fov` should be provided in radians.
343/// * `aspect_ratio` should be the quotient `width / height`.
344///
345/// This matrix is meant to be used when the source coordinate space is right-handed and y-down
346/// (the standard computer graphics coordinate space) and the destination coordinate space is
347/// right-handed and y-down with Z (depth) clip extending from 0.0 (close) to 1.0 (far).
348#[inline]
349pub fn perspective_reversed_infinite_z_vk(
350 vertical_fov: f32,
351 aspect_ratio: f32,
352 z_near: f32,
353) -> Mat4 {
354 let t = (vertical_fov / 2.0).tan();
355 let sy = 1.0 / t;
356 let sx = sy / aspect_ratio;
357
358 Mat4::new(
359 Vec4::new(sx, 0.0, 0.0, 0.0),
360 Vec4::new(0.0, sy, 0.0, 0.0),
361 Vec4::new(0.0, 0.0, 0.0, -1.0),
362 Vec4::new(0.0, 0.0, z_near, 0.0),
363 )
364}