1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#ifndef QSSG_RENDER_CAMERA_H
6#define QSSG_RENDER_CAMERA_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtQuick3DRuntimeRender/private/qtquick3druntimerenderglobal_p.h>
20
21#include <QtQuick3DRuntimeRender/private/qssgrendernode_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrenderray_p.h>
23
24#include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h>
25
26QT_BEGIN_NAMESPACE
27
28struct QSSGCameraGlobalCalculationResult
29{
30 bool m_wasDirty;
31 bool m_computeFrustumSucceeded /* = true */;
32};
33
34struct QSSGRenderCameraConfiguration
35{
36 float dpr = 1.0f;
37 float ssaaMultiplier = 1.0f;
38};
39
40class QSSGRenderCameraFieldOfView
41{
42public:
43 enum class Orientation
44 {
45 Vertical,
46 Horizontal,
47 };
48
49 explicit constexpr QSSGRenderCameraFieldOfView(Orientation orientation = Orientation::Vertical) : fovOrientation(orientation) {}
50 QSSGRenderCameraFieldOfView(const QSSGRenderCameraFieldOfView &) = default;
51 QSSGRenderCameraFieldOfView(QSSGRenderCameraFieldOfView &&) = default;
52
53 QSSGRenderCameraFieldOfView &operator=(const QSSGRenderCameraFieldOfView &other) = default;
54
55 template <Orientation Type = Orientation::Vertical>
56 static QSSGRenderCameraFieldOfView fromDegrees(float fov)
57 {
58 return QSSGRenderCameraFieldOfView(fov, FovValue::Degrees, Type);
59 }
60 template <Orientation Type = Orientation::Vertical>
61 static QSSGRenderCameraFieldOfView fromRadians(float fov)
62 {
63 return QSSGRenderCameraFieldOfView(fov, FovValue::Radians, Type);
64 }
65
66 constexpr Orientation orientation() const { return fovOrientation; }
67
68 float degrees() const { return fovDegrees; }
69 float radians() const { return fovRadians; }
70
71 void setDegrees(float fov)
72 {
73 fovDegrees = fov;
74 fovRadians = qDegreesToRadians(degrees: fov);
75 }
76
77 QSSGRenderCameraFieldOfView asVerticalFov(float aspectRatio) const
78 {
79 if (fovOrientation == Orientation::Vertical)
80 return *this;
81
82 const float fovV = float(2.0 * qAtan(v: qTan(v: qreal(fovRadians) / 2.0) / qreal(aspectRatio)));
83 return fromRadians<Orientation::Vertical>(fov: fovV);
84 }
85
86 void setRadians(float fov)
87 {
88 fovRadians = fov;
89 fovDegrees = qRadiansToDegrees(radians: fov);
90 }
91private:
92 enum class FovValue
93 {
94 Degrees,
95 Radians,
96 };
97 constexpr explicit QSSGRenderCameraFieldOfView(float fov, FovValue value, Orientation angleOfView)
98 : fovDegrees(value == FovValue::Degrees ? fov : qRadiansToDegrees(radians: fov))
99 , fovRadians(value == FovValue::Radians ? fov : qDegreesToRadians(degrees: fov))
100 , fovOrientation(angleOfView)
101 {
102 }
103
104 float fovDegrees = 60.0f;
105 float fovRadians = qDegreesToRadians(degrees: fovDegrees);
106 Orientation fovOrientation;
107};
108
109class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRenderCamera : public QSSGRenderNode
110{
111public:
112 using Configuration = QSSGRenderCameraConfiguration;
113 using FieldOfView = QSSGRenderCameraFieldOfView;
114
115 explicit QSSGRenderCamera(QSSGRenderGraphObject::Type type);
116
117 enum class DirtyFlag : quint8
118 {
119 CameraDirty = 0x1
120 };
121 using FlagT = std::underlying_type_t<DirtyFlag>;
122
123 static constexpr DirtyFlag DirtyMask { std::numeric_limits<FlagT>::max() };
124
125 class ClipPlanes : public QVector2D
126 {
127 public:
128 constexpr inline ClipPlanes() : QVector2D(0.0f, 10000.0f) {}
129 constexpr inline ClipPlanes(float n, float f) : QVector2D(n, f) {}
130 constexpr float clipNear() const noexcept { return x(); }
131 constexpr float clipFar() const noexcept { return y(); }
132
133 constexpr inline void setClipNear(float n) noexcept { setX(n); }
134 constexpr inline void setClipFar(float f) noexcept { setY(f); }
135 };
136
137 class Magnification : public QVector2D
138 {
139 public:
140 constexpr inline Magnification() : QVector2D(1.0f, 1.0f) {}
141 constexpr inline Magnification(float h, float v) : QVector2D(h, v) {}
142 constexpr float horizontal() const noexcept { return x(); }
143 constexpr float vertical() const noexcept { return y(); }
144
145 constexpr inline void setHorizontal(float h) noexcept { setX(h); }
146 constexpr inline void setVertical(float v) noexcept { setY(v); }
147 };
148
149 // Used by the custom frustum camera
150 struct Frustum
151 {
152 float top = 0.0f;
153 float bottom = 0.0f;
154 float left = 0.0f;
155 float right = 0.0f;
156 };
157
158 // Set our position, rotation member variables based on the lookat target
159 // Marks this object as dirty.
160 // Need to test this when the camera's local transform is null.
161 // Assumes parent's local transform is the identity, meaning our local transform is
162 // our global transform.
163 void lookAt(const QVector3D &inCameraPos, const QVector3D &inUpDir, const QVector3D &inTargetPos, const QVector3D &pivot);
164
165 /*!
166 * Convenience function intended for use with internal cameras that's not part of the scene graph!
167 * This function will NOT ensure that the camera's global transform, projection matrix, or state
168 * is updated!.
169 */
170 static bool calculateProjectionInternal(QSSGRenderCamera &camera,
171 const QRectF &inViewport,
172 Configuration config = {});
173
174 /*!
175 * \brief calculateProjection
176 * \param inViewport
177 * \param config
178 * \return true if the projection was successfully calculated, false otherwise.
179 *
180 * This function will calculate the projection matrix for the camera.
181 *
182 * NOTE: This function will not update the camera's global transform. It is the caller's
183 * responsibility to ensure that the camera's global transform has been calculated prior
184 * to calling this function.
185 */
186 bool calculateProjection(const QRectF &inViewport, Configuration config = {});
187
188 void setCustomProjection(const QMatrix4x4 &proj);
189
190 static bool computeFrustumOrtho(QRectF inViewport,
191 QSSGRenderCamera::ClipPlanes clipPlanes,
192 QSSGRenderCamera::Magnification magnification,
193 Configuration config,
194 QMatrix4x4 &outProjection);
195 static bool computeFrustumPerspective(QRectF inViewport,
196 FieldOfView fov,
197 QSSGRenderCamera::ClipPlanes clipPlanes,
198 QMatrix4x4 &outProjection);
199 static bool computeCustomFrustum(QSSGRenderCamera::Frustum frustum,
200 QSSGRenderCamera::ClipPlanes clipPlanes,
201 QMatrix4x4 &outProjection);
202
203 static void calculateViewProjectionMatrix(const QMatrix4x4 &globalTransform,
204 const QMatrix4x4 &projection,
205 QMatrix4x4 &outMatrix);
206
207 void calculateViewProjectionMatrix(const QMatrix4x4 &globalTransform, QMatrix4x4 &outMatrix) const;
208 void calculateViewProjectionWithoutTranslation(const QMatrix4x4 &globalTransform, float near, float far, QMatrix4x4 &outMatrix) const;
209
210 // Unproject a point (x,y) in viewport relative coordinates meaning
211 // left, bottom is 0,0 and values are increasing right,up respectively.
212 QSSGRenderRay unproject(const QMatrix4x4 &globalTransform, const QVector2D &inLayerRelativeMouseCoords, const QRectF &inViewport) const;
213
214 [[nodiscard]] inline bool isDirty(DirtyFlag dirtyFlag = DirtyMask) const
215 {
216 return ((cameraDirtyFlags & FlagT(dirtyFlag)) != 0)
217 || ((dirtyFlag == DirtyMask) && QSSGRenderNode::isDirty());
218 }
219 void markDirty(DirtyFlag dirtyFlag);
220 void clearDirty(DirtyFlag dirtyFlag);
221
222 float getLevelOfDetailMultiplier() const;
223
224 float getDpr() const { return dpr; }
225
226 // Setting these variables should be followed by marking the camera dirty!
227 ClipPlanes clipPlanes;
228 FieldOfView fov;
229 Frustum customFrustum;
230 Magnification magnification;
231 QMatrix4x4 projection;
232 float levelOfDetailPixelThreshold = 1.0;
233 bool enableFrustumClipping = true;
234
235private:
236 // Record some values from creating the projection matrix
237 // to use during mouse picking.
238 QVector2D frustumScale;
239
240 QRectF previousInViewport;
241 float dpr = 1.0f;
242 FlagT cameraDirtyFlags = 0;
243};
244
245[[nodiscard]] constexpr bool qFuzzyCompare(const QSSGRenderCamera::FieldOfView &fov1, const QSSGRenderCamera::FieldOfView &fov2) noexcept
246{
247 return fov1.orientation() == fov2.orientation() && qFuzzyCompare(p1: fov1.degrees(), p2: fov2.degrees());
248}
249
250[[nodiscard]] constexpr bool qFuzzyCompare(QSSGRenderCamera::Frustum f1, QSSGRenderCamera::Frustum f2) noexcept
251{
252 return qFuzzyCompare(p1: f1.top, p2: f2.top) && qFuzzyCompare(p1: f1.bottom, p2: f2.bottom) && qFuzzyCompare(p1: f1.left, p2: f2.left) && qFuzzyCompare(p1: f1.right, p2: f2.right);
253}
254
255QT_END_NAMESPACE
256
257#endif
258

source code of qtquick3d/src/runtimerender/graphobjects/qssgrendercamera_p.h