Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquick3dcamera.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dcamera_p.h"
5
6#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
7
9#include "qquick3dnode_p_p.h"
10
11#include <QtMath>
12#include <QtQuick3DUtils/private/qssgutils_p.h>
13
14#include "qquick3dutils_p.h"
15
17
74
85{
86 return m_frustumCullingEnabled;
87}
88
89void QQuick3DCamera::setFrustumCullingEnabled(bool frustumCullingEnabled)
90{
91 if (m_frustumCullingEnabled == frustumCullingEnabled)
92 return;
93
94 m_frustumCullingEnabled = frustumCullingEnabled;
96 update();
97}
98
110{
111 return m_lookAtNode;
112}
113
115{
116 if (m_lookAtNode == node)
117 return;
118
119 if (m_lookAtNode) {
120 disconnect(m_lookAtNode, &QQuick3DNode::scenePositionChanged, this, &QQuick3DCamera::updateLookAt);
121 disconnect(this, &QQuick3DNode::scenePositionChanged, this, &QQuick3DCamera::updateLookAt);
122 }
123
124 m_lookAtNode = node;
125
126 if (m_lookAtNode) {
127 connect(m_lookAtNode, &QQuick3DNode::scenePositionChanged, this, &QQuick3DCamera::updateLookAt);
128 connect(this, &QQuick3DNode::scenePositionChanged, this, &QQuick3DCamera::updateLookAt);
129 }
130
131 emit lookAtNodeChanged();
132 updateLookAt();
133}
134
151{
152 QSSGRenderCamera *cameraNode = static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(this)->spatialNode);
153 if (!cameraNode)
154 return QVector3D(0, 0, 0);
155
156 QVector4D scenePosRightHand(scenePos, 1);
157
158 // Transform position
159 const QMatrix4x4 sceneToCamera = sceneTransform().inverted();
160 const QMatrix4x4 projectionViewMatrix = cameraNode->projection * sceneToCamera;
161 const QVector4D transformedScenePos = QSSGUtils::mat44::transform(projectionViewMatrix, scenePosRightHand);
162
163 if (qFuzzyIsNull(transformedScenePos.w()) || qIsNaN(transformedScenePos.w()))
164 return QVector3D(0, 0, 0);
165
166 // Normalize scenePosView between [-1, 1]
167 QVector3D scenePosView = transformedScenePos.toVector3D() / transformedScenePos.w();
168
169 // Set z to be the scene distance from clipNear so that the return value
170 // can be used as argument to viewportToscene() to reverse the call.
171 const QVector4D clipNearPos(scenePosView.x(), scenePosView.y(), -1, 1);
172 auto invProj = projectionViewMatrix.inverted();
173 const QVector4D clipNearPosTransformed = QSSGUtils::mat44::transform(invProj, clipNearPos);
174 if (qFuzzyIsNull(clipNearPosTransformed.w()) || qIsNaN(clipNearPosTransformed.w()))
175 return QVector3D(0, 0, 0);
176 const QVector4D clipNearPosScene = clipNearPosTransformed / clipNearPosTransformed.w();
177 QVector4D clipFarPos = clipNearPos;
178 clipFarPos.setZ(0);
179 const QVector4D clipFarPosTransformed = QSSGUtils::mat44::transform(invProj, clipFarPos);
180 if (qFuzzyIsNull(clipFarPosTransformed.w()) || qIsNaN(clipFarPosTransformed.w()))
181 return QVector3D(0, 0, 0);
182 const QVector4D clipFarPosScene = clipFarPosTransformed / clipFarPosTransformed.w();
183 const QVector3D direction = (clipFarPosScene - clipNearPosScene).toVector3D();
184 const QVector3D scenePosVec = (scenePosRightHand - clipNearPosScene).toVector3D();
185
186 const float distanceToScenePos = scenePosVec.length()
187 * (QVector3D::dotProduct(direction, scenePosVec) > 0.f ? 1 : -1);
188
189 scenePosView.setZ(distanceToScenePos);
190
191 // Convert x and y to be between [0, 1]
192 scenePosView.setX((scenePosView.x() / 2) + 0.5f);
193 scenePosView.setY((scenePosView.y() / 2) + 0.5f);
194 // And convert origin from bottom-left to top-left
195 scenePosView.setY(1 - scenePosView.y());
196 return scenePosView;
197}
198
214{
215 QSSGRenderCamera *cameraNode = static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(this)->spatialNode);
216 if (!cameraNode)
217 return QVector3D(0, 0, 0);
218
219 // Pick two positions in the frustum
220 QVector4D clipNearPos(viewportPos, 1);
221 // Convert origin from top-left to bottom-left
222 clipNearPos.setY(1 - clipNearPos.y());
223 // Convert to homogenous position between [-1, 1]
224 clipNearPos.setX((clipNearPos.x() * 2.0f) - 1.0f);
225 clipNearPos.setY((clipNearPos.y() * 2.0f) - 1.0f);
226 QVector4D clipFarPos = clipNearPos;
227 // clipNear: z = -1, clipFar: z = 1. It's recommended to use 0 as
228 // far pos instead of clipFar because of infinite projection issues.
229 clipNearPos.setZ(-1);
230 clipFarPos.setZ(0);
231
232 // Transform position to scene
233 const QMatrix4x4 sceneToCamera = sceneTransform().inverted();
234 const QMatrix4x4 projectionViewMatrixInv = (cameraNode->projection * sceneToCamera).inverted();
235 const QVector4D transformedClipNearPos = QSSGUtils::mat44::transform(projectionViewMatrixInv, clipNearPos);
236 const QVector4D transformedClipFarPos = QSSGUtils::mat44::transform(projectionViewMatrixInv, clipFarPos);
237
238 if (qFuzzyIsNull(transformedClipNearPos.w()) || qIsNaN(transformedClipNearPos.w()) ||
239 qFuzzyIsNull(transformedClipFarPos.w()) || qIsNaN(transformedClipFarPos.w()))
240 return QVector3D(0, 0, 0);
241
242 // Reverse the projection
243 const QVector3D clipNearPosScene = transformedClipNearPos.toVector3D()
244 / transformedClipNearPos.w();
245 const QVector3D clipFarPosScene = transformedClipFarPos.toVector3D()
246 / transformedClipFarPos.w();
247
248 // Calculate the position in the scene
249 const QVector3D direction = (clipFarPosScene - clipNearPosScene).normalized();
250 const float distanceFromClipNear = viewportPos.z();
251 QVector3D scenePos = clipNearPosScene + (direction * distanceFromClipNear);
252
253 return scenePos;
254}
255
260 qreal width,
262{
263 // We can be called before a spatial node is created, if that is the case, create the node now.
264 if (QSSGRenderCamera *cameraNode = static_cast<QSSGRenderCamera *>(updateSpatialNode(QQuick3DObjectPrivate::get(this)->spatialNode))) {
265 QQuick3DObjectPrivate::get(this)->spatialNode = cameraNode;
266 cameraNode->calculateGlobalVariables(QRect(0, 0, width * cameraNode->dpr, height * cameraNode->dpr));
267 }
268
269 return QQuick3DCamera::mapToViewport(scenePos);
270}
271
276 qreal width,
278{
279 // We can be called before a spatial node is created, if that is the case, create the node now.
280 if (QSSGRenderCamera *cameraNode = static_cast<QSSGRenderCamera *>(updateSpatialNode(QQuick3DObjectPrivate::get(this)->spatialNode))) {
281 QQuick3DObjectPrivate::get(this)->spatialNode = cameraNode;
282 cameraNode->calculateGlobalVariables(QRect(0, 0, width * cameraNode->dpr, height * cameraNode->dpr));
283 }
284
285 return QQuick3DCamera::mapFromViewport(viewportPos);
286}
287
296{
297 // Assumption: we never want the camera to roll.
298 // We use Euler angles here to avoid roll to sneak in through numerical instability.
299
300 const auto &targetPosition = scenePos;
301 auto sourcePosition = scenePosition();
302
303 QVector3D targetVector = sourcePosition - targetPosition;
304
305 float yaw = qRadiansToDegrees(atan2(targetVector.x(), targetVector.z()));
306
307 QVector2D p(targetVector.x(), targetVector.z()); // yaw vector projected to horizontal plane
308 float pitch = qRadiansToDegrees(atan2(p.length(), targetVector.y())) - 90;
309
310 const float previousRoll = eulerRotation().z();
311 setEulerRotation(QVector3D(pitch, yaw, previousRoll));
312}
313
322{
323 if (!node)
324 return;
325 lookAt(node->scenePosition());
326}
327
329{
330 QSSGRenderCamera *node = static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(this)->spatialNode);
331 if (node)
332 node->calculateGlobalVariables(inViewport);
333}
334
339{
340 if (!node) {
341 markAllDirty();
343 }
344
346
347 QSSGRenderCamera *camera = static_cast<QSSGRenderCamera *>(node);
348 if (qUpdateIfNeeded(camera->enableFrustumClipping, m_frustumCullingEnabled))
350 if (qUpdateIfNeeded(camera->levelOfDetailPixelThreshold, m_levelOfDetailBias))
352
353 return node;
354}
355
356void QQuick3DCamera::updateLookAt()
357{
358 if (m_lookAtNode)
359 lookAt(m_lookAtNode);
360}
361
387{
388 return m_levelOfDetailBias;
389}
390
391void QQuick3DCamera::setLevelOfDetailBias(float newLevelOfDetailBias)
392{
393 if (qFuzzyCompare(m_levelOfDetailBias, newLevelOfDetailBias))
394 return;
395 m_levelOfDetailBias = newLevelOfDetailBias;
396 emit levelOfDetailBiasChanged();
397 update();
398}
399
401
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
QMatrix4x4 inverted(bool *invertible=nullptr) const
Returns the inverse of this matrix.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QQuick3DNode * lookAtNode
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
Q_INVOKABLE QVector3D mapFromViewport(const QVector3D &viewportPos) const
\qmlmethod vector3d Camera::mapFromViewport(vector3d viewportPos)
void frustumCullingEnabledChanged()
void updateGlobalVariables(const QRectF &inViewport)
void setLookAtNode(QQuick3DNode *node)
Q_INVOKABLE void lookAt(const QVector3D &scenePos)
\qmlmethod vector3d Camera::lookAt(vector3d scenePos)
QQuick3DCamera(QQuick3DNodePrivate &dd, QQuick3DNode *parent=nullptr)
\qmltype Camera \inherits Node \inqmlmodule QtQuick3D
Q_INVOKABLE QVector3D mapToViewport(const QVector3D &scenePos) const
\qmlmethod vector3d Camera::mapToViewport(vector3d scenePos)
float levelOfDetailBias
\qmlproperty float Camera::levelOfDetailBias
void setFrustumCullingEnabled(bool frustumCullingEnabled)
QVector3D scenePosition
void setEulerRotation(const QVector3D &eulerRotation)
void markAllDirty() override
QMatrix4x4 sceneTransform
void scenePositionChanged()
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
QVector3D eulerRotation
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
static constexpr float dotProduct(QVector3D v1, QVector3D v2) noexcept
Returns the dot product of v1 and v2.
Definition qvectornd.h:770
constexpr float z() const noexcept
Returns the z coordinate of this point.
Definition qvectornd.h:672
The QVector4D class represents a vector or vertex in 4D space.
Definition qvectornd.h:330
constexpr void setZ(float z) noexcept
Sets the z coordinate of this point to the given finite z coordinate.
Definition qvectornd.h:885
constexpr float w() const noexcept
Returns the w coordinate of this point.
Definition qvectornd.h:881
QCamera * camera
Definition camera.cpp:19
direction
QVector3D Q_QUICK3DUTILS_EXPORT transform(const QMatrix4x4 &m, const QVector3D &v)
Definition qssgutils.cpp:86
Combined button and popup list for selecting options.
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
bool qIsNaN(qfloat16 f) noexcept
Definition qfloat16.h:284
static QVector3D toVector3D(const QDoubleVector3D &in)
constexpr float qRadiansToDegrees(float radians)
Definition qmath.h:281
GLint GLsizei GLsizei height
GLint GLsizei width
GLenum type
GLint GLenum GLboolean normalized
Definition qopenglext.h:752
GLfloat GLfloat p
[1]
QT_BEGIN_NAMESPACE bool qUpdateIfNeeded(T &orig, T updated)
#define emit
double qreal
Definition qtypes.h:187
myObject disconnect()
[26]
QSSGCameraGlobalCalculationResult calculateGlobalVariables(const QRectF &inViewport)