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