nalgebra_glm/ext/matrix_projection.rs
1use crate::aliases::{TMat4, TVec2, TVec3, TVec4};
2use crate::RealNumber;
3
4/// Define a picking region.
5///
6/// # Parameters:
7///
8/// * `center` - Specify the center of a picking region in window coordinates.
9/// * `delta` - Specify the width and height, respectively, of the picking region in window coordinates.
10/// * `viewport` - Rendering viewport.
11pub fn pick_matrix<T: RealNumber>(
12 center: &TVec2<T>,
13 delta: &TVec2<T>,
14 viewport: &TVec4<T>,
15) -> TMat4<T> {
16 let shift = TVec3::new(
17 (viewport.z - (center.x - viewport.x) * na::convert(2.0)) / delta.x,
18 (viewport.w - (center.y - viewport.y) * na::convert(2.0)) / delta.y,
19 T::zero(),
20 );
21
22 let result = TMat4::new_translation(&shift);
23 result.prepend_nonuniform_scaling(&TVec3::new(
24 viewport.z / delta.x,
25 viewport.w / delta.y,
26 T::one(),
27 ))
28}
29
30/// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates with a
31/// depth range of -1 to 1
32///
33/// # Parameters:
34///
35/// * `obj` - Specify the object coordinates.
36/// * `model` - Specifies the current modelview matrix.
37/// * `proj` - Specifies the current projection matrix.
38/// * `viewport` - Specifies the current viewport.
39///
40/// # See also:
41///
42/// * [`project_no()`]
43/// * [`project_zo()`]
44/// * [`unproject()`]
45/// * [`unproject_no()`]
46/// * [`unproject_zo()`]
47pub fn project<T: RealNumber>(
48 obj: &TVec3<T>,
49 model: &TMat4<T>,
50 proj: &TMat4<T>,
51 viewport: TVec4<T>,
52) -> TVec3<T> {
53 project_no(obj, model, proj, viewport)
54}
55
56/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
57///
58/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)
59///
60/// # Parameters:
61///
62/// * `obj` - Specify the object coordinates.
63/// * `model` - Specifies the current modelview matrix.
64/// * `proj` - Specifies the current projection matrix.
65/// * `viewport` - Specifies the current viewport.
66///
67/// # See also:
68///
69/// * [`project()`]
70/// * [`project_zo()`]
71/// * [`unproject()`]
72/// * [`unproject_no()`]
73/// * [`unproject_zo()`]
74pub fn project_no<T: RealNumber>(
75 obj: &TVec3<T>,
76 model: &TMat4<T>,
77 proj: &TMat4<T>,
78 viewport: TVec4<T>,
79) -> TVec3<T> {
80 let proj = project_zo(obj, model, proj, viewport);
81 TVec3::new(proj.x, proj.y, proj.z * na::convert(0.5) + na::convert(0.5))
82}
83
84/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
85///
86/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)
87///
88/// # Parameters:
89///
90/// * `obj` - Specify the object coordinates.
91/// * `model` - Specifies the current modelview matrix.
92/// * `proj` - Specifies the current projection matrix.
93/// * `viewport` - Specifies the current viewport.
94///
95/// # See also:
96///
97/// * [`project()`]
98/// * [`project_no()`]
99/// * [`unproject()`]
100/// * [`unproject_no()`]
101/// * [`unproject_zo()`]
102pub fn project_zo<T: RealNumber>(
103 obj: &TVec3<T>,
104 model: &TMat4<T>,
105 proj: &TMat4<T>,
106 viewport: TVec4<T>,
107) -> TVec3<T> {
108 let normalized = proj * model * TVec4::new(obj.x, obj.y, obj.z, T::one());
109 let scale = T::one() / normalized.w;
110
111 TVec3::new(
112 viewport.x + (viewport.z * (normalized.x * scale + T::one()) * na::convert(0.5)),
113 viewport.y + (viewport.w * (normalized.y * scale + T::one()) * na::convert(0.5)),
114 normalized.z * scale,
115 )
116}
117
118/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using a
119/// depth range of -1 to 1
120///
121/// # Parameters:
122///
123/// * `obj` - Specify the window coordinates to be mapped.
124/// * `model` - Specifies the current modelview matrix.
125/// * `proj` - Specifies the current projection matrix.
126/// * `viewport` - Specifies the current viewport.
127///
128/// # See also:
129///
130/// * [`project()`]
131/// * [`project_no()`]
132/// * [`project_zo()`]
133/// * [`unproject_no()`]
134/// * [`unproject_zo()`]
135pub fn unproject<T: RealNumber>(
136 win: &TVec3<T>,
137 model: &TMat4<T>,
138 proj: &TMat4<T>,
139 viewport: TVec4<T>,
140) -> TVec3<T> {
141 unproject_no(win, model, proj, viewport)
142}
143
144/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
145///
146/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)
147///
148/// # Parameters:
149///
150/// * `obj` - Specify the window coordinates to be mapped.
151/// * `model` - Specifies the current modelview matrix.
152/// * `proj` - Specifies the current projection matrix.
153/// * `viewport` - Specifies the current viewport.
154///
155/// # See also:
156///
157/// * [`project()`]
158/// * [`project_no()`]
159/// * [`project_zo()`]
160/// * [`unproject()`]
161/// * [`unproject_zo()`]
162pub fn unproject_no<T: RealNumber>(
163 win: &TVec3<T>,
164 model: &TMat4<T>,
165 proj: &TMat4<T>,
166 viewport: TVec4<T>,
167) -> TVec3<T> {
168 let _2: T = na::convert(2.0);
169 let transform = (proj * model).try_inverse().unwrap_or_else(TMat4::zeros);
170 let pt = TVec4::new(
171 _2 * (win.x - viewport.x) / viewport.z - T::one(),
172 _2 * (win.y - viewport.y) / viewport.w - T::one(),
173 _2 * win.z - T::one(),
174 T::one(),
175 );
176
177 let result = transform * pt;
178 result.fixed_rows::<3>(0) / result.w
179}
180
181/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
182///
183/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)
184///
185/// # Parameters:
186///
187/// * `obj` - Specify the window coordinates to be mapped.
188/// * `model` - Specifies the current modelview matrix.
189/// * `proj` - Specifies the current projection matrix.
190/// * `viewport` - Specifies the current viewport.
191///
192/// # See also:
193///
194/// * [`project()`]
195/// * [`project_no()`]
196/// * [`project_zo()`]
197/// * [`unproject()`]
198/// * [`unproject_no()`]
199pub fn unproject_zo<T: RealNumber>(
200 win: &TVec3<T>,
201 model: &TMat4<T>,
202 proj: &TMat4<T>,
203 viewport: TVec4<T>,
204) -> TVec3<T> {
205 let _2: T = na::convert(2.0);
206 let transform = (proj * model).try_inverse().unwrap_or_else(TMat4::zeros);
207 let pt = TVec4::new(
208 _2 * (win.x - viewport.x) / viewport.z - T::one(),
209 _2 * (win.y - viewport.y) / viewport.w - T::one(),
210 win.z,
211 T::one(),
212 );
213
214 let result = transform * pt;
215 result.fixed_rows::<3>(0) / result.w
216}