Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qssgrendercamera.cpp
Go to the documentation of this file.
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
// Qt-Security score:significant reason:default
5
6
7
8
#
include
"qssgrendercamera_p.h"
9
10
#
include
<
QtQuick3DRuntimeRender
/
private
/
qssgrendererutil_p
.
h
>
11
12
#
include
<
QtQuick3DUtils
/
private
/
qssgutils_p
.
h
>
13
14
#
include
<
QtGui
/
qquaternion
.
h
>
15
#
include
<
QtGui
/
QVector2D
>
16
17
#
include
<
qmath
.
h
>
18
19
QT_BEGIN_NAMESPACE
20
21
static
inline
float
getAspectRatio
(
const
QRectF &inViewport)
22
{
23
return
inViewport.height() != 0 ? inViewport.width() / inViewport.height() : 0.0f;
24
}
25
26
QSSGRenderCamera::QSSGRenderCamera(QSSGRenderGraphObject::Type type)
27
: QSSGRenderNode(type)
28
{
29
Q_ASSERT(QSSGRenderCamera::isCamera(type));
30
markDirty(DirtyFlag::CameraDirty);
31
}
32
33
bool
QSSGRenderCamera::calculateProjectionInternal(QSSGRenderCamera &camera,
34
const
QRectF &inViewport,
35
Configuration config)
36
{
37
return
camera.calculateProjection(inViewport, config);
38
}
39
40
bool
QSSGRenderCamera::calculateProjection(
const
QRectF &inViewport, Configuration config)
41
{
42
bool
retval =
false
;
43
44
// NOTE: We always update the dpr, under normal surcumstances it won't change, but we have at least
45
// one broken use-cases (front-end camera class) where we depend on the dpr being available from
46
// here...
47
dpr = config.dpr;
48
49
const
bool
argumentsChanged = inViewport != previousInViewport;
50
if
(!argumentsChanged && !isDirty(DirtyFlag::CameraDirty))
51
return
true
;
52
previousInViewport = inViewport;
53
clearDirty(DirtyFlag::CameraDirty);
54
55
switch
(type) {
56
case
QSSGRenderGraphObject::Type::OrthographicCamera:
57
retval = computeFrustumOrtho(inViewport, clipPlanes, magnification, config, projection);
58
break
;
59
case
QSSGRenderGraphObject::Type::PerspectiveCamera:
60
retval = computeFrustumPerspective(inViewport, fov, clipPlanes, projection);
61
break
;
62
case
QSSGRenderGraphObject::Type::CustomCamera:
63
retval =
true
;
// Do nothing
64
break
;
65
case
QSSGRenderGraphObject::Type::CustomFrustumCamera:
66
retval = computeCustomFrustum(customFrustum, clipPlanes, projection);
67
break
;
68
default
:
69
Q_UNREACHABLE();
70
}
71
72
if
(retval) {
73
float
*writePtr(projection.data());
74
frustumScale.setX(writePtr[0]);
75
frustumScale.setY(writePtr[5]);
76
}
77
return
retval;
78
}
79
80
//==============================================================================
81
/**
82
* Compute the projection matrix for a perspective camera
83
* @return true if the computed projection matrix is valid
84
*/
85
bool
QSSGRenderCamera::computeFrustumPerspective(QRectF inViewport,
86
QSSGRenderCamera::FieldOfView fov,
87
QSSGRenderCamera::ClipPlanes clipPlane,
88
QMatrix4x4 &outProjection)
89
{
90
outProjection.setToIdentity();
91
const
float
aspectRatio = getAspectRatio(inViewport);
92
const
auto
vfov = fov.asVerticalFov(aspectRatio);
93
outProjection.perspective(vfov.degrees(), aspectRatio, clipPlane.clipNear(), clipPlane.clipFar());
94
return
true
;
95
}
96
97
bool
QSSGRenderCamera::computeCustomFrustum(QSSGRenderCamera::Frustum frustum,
98
QSSGRenderCamera::ClipPlanes clipPlanes,
99
QMatrix4x4 &outProjection)
100
{
101
outProjection.setToIdentity();
102
outProjection.frustum(frustum.left, frustum.right, frustum.bottom, frustum.top, clipPlanes.clipNear(), clipPlanes.clipFar());
103
return
true
;
104
}
105
106
void
QSSGRenderCamera::calculateViewProjectionMatrix(
const
QMatrix4x4 &globalTransform,
107
const
QMatrix4x4 &projection,
108
QMatrix4x4 &outMatrix)
109
{
110
QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
111
nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
112
nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
113
nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
114
nonScaledGlobal.setColumn(3, globalTransform.column(3));
115
outMatrix = projection * nonScaledGlobal.inverted();
116
}
117
118
//==============================================================================
119
/**
120
* Compute the outProjection matrix for a orthographic camera
121
* @return true if the computed outProjection matrix is valid
122
*/
123
bool
QSSGRenderCamera::computeFrustumOrtho(QRectF inViewport,
124
QSSGRenderCamera::ClipPlanes clipPlanes,
125
QSSGRenderCamera::Magnification magnification,
126
Configuration config,
127
QMatrix4x4 &outProjection)
128
{
129
130
131
outProjection.setToIdentity();
132
// When using ssaa we need to zoom with the ssaa multiplier since otherwise the
133
// orthographic camera will be zoomed out due to the bigger viewport. We therefore
134
// scale the magnification before calulating the projection.
135
// Since the same camera can be used in several View3Ds with or without ssaa we
136
// cannot store the magnification permanently.
137
magnification *= config.ssaaMultiplier;
138
const
float
halfWidth = inViewport.width() / 2.0f / magnification.horizontal() / config.dpr;
139
const
float
halfHeight = inViewport.height() / 2.0f / magnification.vertical() / config.dpr;
140
outProjection.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, clipPlanes.clipNear(), clipPlanes.clipFar());
141
return
true
;
142
}
143
144
static
QQuaternion
rotationQuaternionForLookAt
(
const
QVector3D &sourcePosition,
145
const
QVector3D &sourceDirection,
146
const
QVector3D &targetPosition,
147
const
QVector3D &upDirection)
148
{
149
QVector3D targetDirection = sourcePosition - targetPosition;
150
targetDirection.normalize();
151
152
QVector3D rotationAxis = QVector3D::crossProduct(sourceDirection, targetDirection);
153
154
const
QVector3D normalizedAxis = rotationAxis.normalized();
155
if
(qFuzzyIsNull(normalizedAxis.lengthSquared()))
156
rotationAxis = upDirection;
157
158
float
dot = QVector3D::dotProduct(sourceDirection, targetDirection);
159
dot = qBound(-1.0f, dot, 1.0f);
160
float
rotationAngle =
float
(qRadiansToDegrees(qAcos(qreal(dot))));
161
162
return
QQuaternion::fromAxisAndAngle(rotationAxis, rotationAngle);
163
}
164
165
void
QSSGRenderCamera::lookAt(
const
QVector3D &inCameraPos,
const
QVector3D &inUpDir,
const
QVector3D &inTargetPos,
const
QVector3D &pivot)
166
{
167
QQuaternion rotation = rotationQuaternionForLookAt(inCameraPos, getScalingCorrectDirection(localTransform), inTargetPos, inUpDir.normalized());
168
localTransform = QSSGRenderNode::calculateTransformMatrix(inCameraPos, QSSGRenderNode::initScale, pivot, rotation);
169
QSSGRenderNode::markDirty(QSSGRenderNode::DirtyFlag::TransformDirty);
170
}
171
172
void
QSSGRenderCamera::calculateViewProjectionMatrix(
const
QMatrix4x4 &globalTransform, QMatrix4x4 &outMatrix)
const
173
{
174
QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
175
nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
176
nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
177
nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
178
nonScaledGlobal.setColumn(3, globalTransform.column(3));
179
outMatrix = projection * nonScaledGlobal.inverted();
180
}
181
182
void
QSSGRenderCamera::calculateViewProjectionWithoutTranslation(
const
QMatrix4x4 &globalTransform,
float
clipNear,
float
clipFar, QMatrix4x4 &outMatrix)
const
183
{
184
if
(qFuzzyIsNull(clipFar - clipNear)) {
185
qWarning() <<
"QSSGRenderCamera::calculateViewProjection: far == near"
;
186
return
;
187
}
188
189
QMatrix4x4 proj = projection;
190
proj(2, 2) = -(clipFar + clipNear) / (clipFar - clipNear);
191
proj(2, 3) = -2 * clipFar * clipNear / (clipFar - clipNear);
192
QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
193
nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
194
nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
195
nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
196
nonScaledGlobal.setColumn(3, QVector4D(0, 0, 0, 1));
197
outMatrix = proj * nonScaledGlobal.inverted();
198
}
199
200
QSSGRenderRay QSSGRenderCamera::unproject(
const
QMatrix4x4 &globalTransform,
201
const
QVector2D &inViewportRelativeCoords,
202
const
QRectF &inViewport)
const
203
{
204
QSSGRenderRay theRay;
205
QVector2D normalizedCoords = QSSGUtils::rect::relativeToNormalizedCoordinates(inViewport, inViewportRelativeCoords);
206
QVector3D &outOrigin(theRay.origin);
207
QVector3D &outDir(theRay.direction);
208
QVector2D inverseFrustumScale(1.0f / frustumScale.x(), 1.0f / frustumScale.y());
209
QVector2D scaledCoords(inverseFrustumScale.x() * normalizedCoords.x(), inverseFrustumScale.y() * normalizedCoords.y());
210
211
if
(type == QSSGRenderCamera::Type::OrthographicCamera) {
212
outOrigin.setX(scaledCoords.x());
213
outOrigin.setY(scaledCoords.y());
214
outOrigin.setZ(0.0f);
215
216
outDir.setX(0.0f);
217
outDir.setY(0.0f);
218
outDir.setZ(-1.0f);
219
}
else
{
220
outOrigin.setX(0.0f);
221
outOrigin.setY(0.0f);
222
outOrigin.setZ(0.0f);
223
224
outDir.setX(scaledCoords.x());
225
outDir.setY(scaledCoords.y());
226
outDir.setZ(-1.0f);
227
}
228
229
outOrigin = QSSGUtils::mat44::transform(globalTransform, outOrigin);
230
QMatrix3x3 theNormalMatrix = globalTransform.normalMatrix();
231
232
outDir = QSSGUtils::mat33::transform(theNormalMatrix, outDir);
233
outDir.normalize();
234
235
return
theRay;
236
}
237
238
void
QSSGRenderCamera::markDirty(DirtyFlag dirtyFlag)
239
{
240
cameraDirtyFlags |= FlagT(dirtyFlag);
241
QSSGRenderNode::markDirty(QSSGRenderNode::DirtyFlag::SubNodeDirty);
242
}
243
244
void
QSSGRenderCamera::clearDirty(DirtyFlag dirtyFlag)
245
{
246
cameraDirtyFlags &= ~FlagT(dirtyFlag);
247
QSSGRenderNode::clearDirty(QSSGRenderNode::DirtyFlag::SubNodeDirty);
248
}
249
250
static
float
getZNear
(
const
QMatrix4x4 &projection)
251
{
252
const
float
*data = projection.constData();
253
QSSGPlane plane(QVector3D(data[3] + data[2], data[7] + data[6], data[11] + data[10]), -data[15] - data[14]);
254
plane.normalize();
255
return
plane.d;
256
}
257
258
static
QVector2D
getViewportHalfExtents
(
const
QMatrix4x4 &projection) {
259
const
float
*data = projection.constData();
260
261
QSSGPlane nearPlane(QVector3D(data[3] + data[2], data[7] + data[6], data[11] + data[10]), -data[15] - data[14]);
262
nearPlane.normalize();
263
QSSGPlane rightPlane(QVector3D(data[3] - data[0], data[7] - data[4], data[11] - data[8]), -data[15] + data[12]);
264
rightPlane.normalize();
265
QSSGPlane topPlane(QVector3D(data[3] - data[1], data[7] - data[5], data[11] - data[9]), -data[15] + data[13]);
266
topPlane.normalize();
267
268
// Get intersection the 3 planes
269
float
denom = QVector3D::dotProduct(QVector3D::crossProduct(nearPlane.n, rightPlane.n), topPlane.n);
270
if
(qFuzzyIsNull(denom))
271
return
QVector2D();
272
273
QVector3D intersection = (QVector3D::crossProduct(rightPlane.n, topPlane.n) * nearPlane.d +
274
(QVector3D::crossProduct(topPlane.n, nearPlane.n) * rightPlane.d) +
275
(QVector3D::crossProduct(nearPlane.n, rightPlane.n) * topPlane.d)) / denom;
276
277
return
QVector2D(intersection.x(), intersection.y());
278
}
279
280
float
QSSGRenderCamera::getLevelOfDetailMultiplier()
const
281
{
282
if
(type == QSSGRenderGraphObject::Type::OrthographicCamera)
283
return
getViewportHalfExtents(projection).x();
284
285
float
zn = getZNear(projection);
286
float
width = getViewportHalfExtents(projection).x() * 2.0;
287
return
1.0 / (zn / width);
288
289
}
290
291
QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
getViewportHalfExtents
static QVector2D getViewportHalfExtents(const QMatrix4x4 &projection)
Definition
qssgrendercamera.cpp:258
getZNear
static float getZNear(const QMatrix4x4 &projection)
Definition
qssgrendercamera.cpp:250
getAspectRatio
static QT_BEGIN_NAMESPACE float getAspectRatio(const QRectF &inViewport)
Definition
qssgrendercamera.cpp:21
rotationQuaternionForLookAt
static QQuaternion rotationQuaternionForLookAt(const QVector3D &sourcePosition, const QVector3D &sourceDirection, const QVector3D &targetPosition, const QVector3D &upDirection)
Definition
qssgrendercamera.cpp:144
qtquick3d
src
runtimerender
graphobjects
qssgrendercamera.cpp
Generated on
for Qt by
1.18.0