Visual Computing Library
Loading...
Searching...
No Matches
matrix.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_RENDER_VIEWER_MATRIX_H
24#define VCL_RENDER_VIEWER_MATRIX_H
25
26#include <vclib/space/core/matrix.h>
27#include <vclib/space/core/point.h>
28
29namespace vcl {
30
31enum Handedness { LEFT_HAND, RIGHT_HAND };
32
33namespace detail {
34
35template<typename Scalar>
36void projectionMatrixXYWH(
37 auto* res,
38 Scalar x,
39 Scalar y,
40 Scalar width,
41 Scalar height,
42 Scalar nearPlane,
43 Scalar farPlane,
44 bool homogeneousNDC,
45 Handedness handedness = RIGHT_HAND)
46{
47 // note: don't use 'near' and 'far' variable names, as they are already
48 // defined in windows.h headers
49 Scalar diff = farPlane - nearPlane;
50 Scalar a = homogeneousNDC ? (farPlane + nearPlane) / diff : farPlane / diff;
51 Scalar b =
52 homogeneousNDC ? (2.0 * farPlane * nearPlane) / diff : nearPlane * a;
53
54 std::fill(res, res + 16, 0);
55
56 res[0] = width;
57 res[5] = height;
58 res[8] = handedness == RIGHT_HAND ? x : -x;
59 res[9] = handedness == RIGHT_HAND ? y : -y;
60 res[10] = handedness == RIGHT_HAND ? -a : a;
61 res[11] = handedness == RIGHT_HAND ? -1.0 : 1.0;
62 res[14] = -b;
63}
64
65} // namespace detail
66
81template<Point3Concept PointType>
82void lookAtMatrix(
83 auto* res,
84 const PointType& eye,
85 const PointType& center,
86 const PointType& up,
87 Handedness handedness = RIGHT_HAND)
88{
89 if (center != eye) {
90 PointType zaxis = handedness == RIGHT_HAND ?
91 (eye - center).normalized() :
92 (center - eye).normalized();
93
94 PointType xaxis = up.cross(zaxis);
95
96 if (xaxis.dot(xaxis) == 0) {
97 xaxis = handedness == RIGHT_HAND ? PointType(1, 0, 0) :
98 PointType(-1, 0, 0);
99 }
100 else {
101 xaxis = xaxis.normalized();
102 }
103
104 PointType yaxis = zaxis.cross(xaxis);
105
106 res[0] = xaxis.x();
107 res[1] = yaxis.x();
108 res[2] = zaxis.x();
109 res[3] = 0.0f;
110
111 res[4] = xaxis.y();
112 res[5] = yaxis.y();
113 res[6] = zaxis.y();
114 res[7] = 0.0f;
115
116 res[8] = xaxis.z();
117 res[9] = yaxis.z();
118 res[10] = zaxis.z();
119 res[11] = 0.0f;
120
121 res[12] = -xaxis.dot(eye);
122 res[13] = -yaxis.dot(eye);
123 res[14] = -zaxis.dot(eye);
124 res[15] = 1.0f;
125 }
126}
127
141template<MatrixConcept Matrix44, Point3Concept PointType>
142Matrix44 lookAtMatrix(
143 const PointType& eye,
144 const PointType& center,
145 const PointType& up,
146 Handedness handedness = RIGHT_HAND)
147{
148 Matrix44 res(4, 4);
149 lookAtMatrix(res.data(), eye, center, up, handedness);
150 return res;
151}
152
166template<Point3Concept PointType>
167void lookAtMatrixLeftHanded(
168 auto* res,
169 const PointType& eye,
170 const PointType& center,
171 const PointType& up)
172{
173 lookAtMatrix(res, eye, center, up, LEFT_HAND);
174}
175
188template<MatrixConcept Matrix44, Point3Concept PointType>
189Matrix44 lookAtMatrixLeftHanded(
190 const PointType& eye,
191 const PointType& center,
192 const PointType& up)
193{
194 Matrix44 res(4, 4);
195 lookAtMatrix(res.data(), eye, center, up, LEFT_HAND);
196 return res;
197}
198
199template<typename Scalar>
200void projectionMatrix(
201 auto* res,
202 Scalar fov,
203 Scalar aspect,
204 Scalar nearPlane,
205 Scalar farPlane,
206 bool homogeneousNDC,
207 Handedness handedness = RIGHT_HAND)
208{
209 Scalar h = 1.0 / std::tan(vcl::toRad(fov) * 0.5);
210 Scalar w = h * 1.0 / aspect;
211 detail::projectionMatrixXYWH(
212 res,
213 (Scalar) 0,
214 (Scalar) 0,
215 w,
216 h,
217 nearPlane,
218 farPlane,
219 homogeneousNDC,
220 handedness);
221}
222
223template<MatrixConcept Matrix44, typename Scalar>
224Matrix44 projectionMatrix(
225 Scalar fov,
226 Scalar aspect,
227 Scalar nearPlane,
228 Scalar farPlane,
229 bool homogeneousNDC,
230 Handedness handedness = RIGHT_HAND)
231{
232 Matrix44 res(4, 4);
233 projectionMatrix(
234 res.data(),
235 fov,
236 aspect,
237 nearPlane,
238 farPlane,
239 homogeneousNDC,
240 handedness);
241 return res;
242}
243
244template<typename Scalar>
245void projectionMatrixLeftHanded(
246 auto* res,
247 Scalar fov,
248 Scalar aspect,
249 Scalar nearPlane,
250 Scalar farPlane,
251 bool homogeneousNDC)
252{
253 Scalar h = 1.0 / std::tan(vcl::toRad(fov) * 0.5);
254 Scalar w = h * 1.0 / aspect;
255 projectionMatrix(
256 res, fov, aspect, nearPlane, farPlane, homogeneousNDC, LEFT_HAND);
257}
258
259template<MatrixConcept Matrix44, typename Scalar>
260Matrix44 projectionMatrixLeftHanded(
261 Scalar fov,
262 Scalar aspect,
263 Scalar nearPlane,
264 Scalar farPlane,
265 bool homogeneousNDC)
266{
267 Matrix44 res(4, 4);
268 projectionMatrix(
269 res.data(),
270 fov,
271 aspect,
272 nearPlane,
273 farPlane,
274 homogeneousNDC,
275 LEFT_HAND);
276 return res;
277}
278
279template<typename Scalar>
280void orthoProjectionMatrix(
281 auto* res,
282 Scalar left,
283 Scalar right,
284 Scalar top,
285 Scalar bottom,
286 Scalar nearPlane,
287 Scalar farPlane,
288 bool homogeneousNDC,
289 Handedness handedness = RIGHT_HAND)
290{
291 // note: don't use 'near' and 'far' variable names, as they are already
292 // defined in windows.h headers
293 Scalar c = homogeneousNDC ? 2.0 / (farPlane - nearPlane) :
294 1.0 / (farPlane - nearPlane);
295 Scalar f = homogeneousNDC ?
296 (farPlane + nearPlane) / (nearPlane - farPlane) :
297 nearPlane / (nearPlane - farPlane);
298
299 std::fill(res, res + 16, 0);
300 res[0] = 2.0 / (right - left);
301 res[5] = 2.0 / (top - bottom);
302 res[10] = RIGHT_HAND ? -c : c;
303 res[12] = (right + left) / (left - right);
304 res[13] = (bottom + top) / (bottom - top);
305 res[14] = f;
306 res[15] = 1.0;
307}
308
309template<MatrixConcept Matrix44, typename Scalar>
310Matrix44 orthoProjectionMatrix(
311 Scalar left,
312 Scalar right,
313 Scalar top,
314 Scalar bottom,
315 Scalar nearPlane,
316 Scalar farPlane,
317 bool homogeneousNDC,
318 Handedness handedness = RIGHT_HAND)
319{
320 Matrix44 res(4, 4);
321 orthoProjectionMatrix(
322 res.data(),
323 left,
324 right,
325 top,
326 bottom,
327 nearPlane,
328 farPlane,
329 homogeneousNDC,
330 handedness);
331 return res;
332}
333
349template<MatrixConcept Matrix44, Point3Concept PointType>
350PointType unproject(
351 const PointType& screenPos,
352 const Matrix44& modelViewProjection,
353 const Point4<typename Matrix44::Scalar>& viewport,
354 bool homogeneousNDC)
355{
356 using Scalar = Matrix44::Scalar;
357 const Matrix44 inv = modelViewProjection.inverse();
358 Point4<Scalar> p(
359 (screenPos.x() - viewport[0]) / viewport[2] * 2.0 - 1.0,
360 (screenPos.y() - viewport[1]) / viewport[3] * 2.0 - 1.0,
361 homogeneousNDC ? 2.0 * screenPos.z() - 1.0 : screenPos.z(),
362 1.0);
363 p = inv * p;
364 if (p.w() == 0.0) {
365 throw std::runtime_error("unproject: division by zero");
366 }
367 return p.template head<3>() / p.w();
368}
369
370} // namespace vcl
371
372#endif // VCL_RENDER_VIEWER_MATRIX_H
Scalar toRad(const Scalar &deg)
Converts an angle in degrees to radians.
Definition base.h:83