Qt 6.x
The Qt SDK
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
5
7
8#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
9
10#include <QtQuick3DUtils/private/qssgutils_p.h>
11
12#include <QtGui/QVector2D>
13
14#include <qmath.h>
15
17
18namespace {
19
20float getAspectRatio(const QRectF &inViewport)
21{
22 return inViewport.height() != 0 ? inViewport.width() / inViewport.height() : 0.0f;
23}
24
25}
26
29 , clipNear(10)
30 , clipFar(10000)
31 , fov(qDegreesToRadians(60.0f))
32 , fovHorizontal(false)
33 , enableFrustumClipping(true)
34{
37}
38
39// Code for testing
41{
43 return QSSGCameraGlobalCalculationResult{ wasDirty, calculateProjection(inViewport) };
44}
45
47{
48 bool retval = false;
49
50 const bool argumentsChanged = inViewport != previousInViewport;
51 if (!argumentsChanged && !isDirty(DirtyFlag::CameraDirty))
52 return true;
53 previousInViewport = inViewport;
55
56 switch (type) {
57 case QSSGRenderGraphObject::Type::OrthographicCamera:
58 retval = computeFrustumOrtho(inViewport);
59 break;
60 case QSSGRenderGraphObject::Type::PerspectiveCamera:
61 retval = computeFrustumPerspective(inViewport);
62 break;
63 case QSSGRenderGraphObject::Type::CustomCamera:
64 retval = true; // Do nothing
65 break;
66 case QSSGRenderGraphObject::Type::CustomFrustumCamera:
67 retval = computeCustomFrustum(inViewport);
68 break;
69 default:
70 Q_UNREACHABLE();
71 }
72
73 if (retval) {
74 float *writePtr(projection.data());
75 frustumScale.setX(writePtr[0]);
76 frustumScale.setY(writePtr[5]);
77 }
78 return retval;
79}
80
81//==============================================================================
87{
89 projection.perspective(qRadiansToDegrees(verticalFov(inViewport)), getAspectRatio(inViewport), clipNear, clipFar);
90 return true;
91}
92
94{
95 Q_UNUSED(inViewport);
98 return true;
99}
100
101//==============================================================================
107{
109 float halfWidth = inViewport.width() / 2.0f / horizontalMagnification / dpr;
110 float halfHeight = inViewport.height() / 2.0f / verticalMagnification / dpr;
111 projection.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, clipNear, clipFar);
112 return true;
113}
114
116{
117 Q_UNUSED(inViewport);
119}
120
122 const QVector3D &sourceDirection,
123 const QVector3D &targetPosition,
124 const QVector3D &upDirection)
125{
126 QVector3D targetDirection = sourcePosition - targetPosition;
127 targetDirection.normalize();
128
129 QVector3D rotationAxis = QVector3D::crossProduct(sourceDirection, targetDirection);
130
131 const QVector3D normalizedAxis = rotationAxis.normalized();
132 if (qFuzzyIsNull(normalizedAxis.lengthSquared()))
133 rotationAxis = upDirection;
134
135 float dot = QVector3D::dotProduct(sourceDirection, targetDirection);
136 float rotationAngle = float(qRadiansToDegrees(qAcos(qreal(dot))));
137
138 return QQuaternion::fromAxisAndAngle(rotationAxis, rotationAngle);
139}
140
141void QSSGRenderCamera::lookAt(const QVector3D &inCameraPos, const QVector3D &inUpDir, const QVector3D &inTargetPos, const QVector3D &pivot)
142{
143 QQuaternion rotation = rotationQuaternionForLookAt(inCameraPos, getScalingCorrectDirection(), inTargetPos, inUpDir.normalized());
146}
147
149{
150 QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
151 nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
152 nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
153 nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
154 nonScaledGlobal.setColumn(3, globalTransform.column(3));
155 outMatrix = projection * nonScaledGlobal.inverted();
156}
157
158void QSSGRenderCamera::calculateViewProjectionWithoutTranslation(float clipNear, float clipFar, QMatrix4x4 &outMatrix) const
159{
161 qWarning() << "QSSGRenderCamera::calculateViewProjection: far == near";
162 return;
163 }
164
165 QMatrix4x4 proj = projection;
166 proj(2, 2) = -(clipFar + clipNear) / (clipFar - clipNear);
167 proj(2, 3) = -2 * clipFar * clipNear / (clipFar - clipNear);
168 QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
169 nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
170 nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
171 nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
172 nonScaledGlobal.setColumn(3, QVector4D(0, 0, 0, 1));
173 outMatrix = proj * nonScaledGlobal.inverted();
174}
175
177 const QRectF &inViewport) const
178{
179 QSSGRenderRay theRay;
180 QVector2D normalizedCoords = relativeToNormalizedCoordinates(inViewport, inViewportRelativeCoords);
181 QVector3D &outOrigin(theRay.origin);
182 QVector3D &outDir(theRay.direction);
183 QVector2D inverseFrustumScale(1.0f / frustumScale.x(), 1.0f / frustumScale.y());
184 QVector2D scaledCoords(inverseFrustumScale.x() * normalizedCoords.x(), inverseFrustumScale.y() * normalizedCoords.y());
185
186 if (type == QSSGRenderCamera::Type::OrthographicCamera) {
187 outOrigin.setX(scaledCoords.x());
188 outOrigin.setY(scaledCoords.y());
189 outOrigin.setZ(0.0f);
190
191 outDir.setX(0.0f);
192 outDir.setY(0.0f);
193 outDir.setZ(-1.0f);
194 } else {
195 outOrigin.setX(0.0f);
196 outOrigin.setY(0.0f);
197 outOrigin.setZ(0.0f);
198
199 outDir.setX(scaledCoords.x());
200 outDir.setY(scaledCoords.y());
201 outDir.setZ(-1.0f);
202 }
203
204 outOrigin = mat44::transform(globalTransform, outOrigin);
205 QMatrix3x3 theNormalMatrix = calculateNormalMatrix();
206
207 outDir = mat33::transform(theNormalMatrix, outDir);
208 outDir.normalize();
209
210 return theRay;
211}
212
214{
215 QVector3D theCameraDir = getDirection();
216 QVector3D theObjGlobalPos = inGlobalPos;
217 float theDistance = -1.0f * QVector3D::dotProduct(theObjGlobalPos, theCameraDir);
218 QSSGPlane theCameraPlane(theCameraDir, theDistance);
219 return QSSGRenderRay::intersect(theCameraPlane, inRay).value_or(QVector3D{});
220}
221
222float QSSGRenderCamera::verticalFov(float aspectRatio) const
223{
224 return fovHorizontal ? float(2.0 * qAtan(qTan(qreal(fov) / 2.0) / qreal(aspectRatio))) : fov;
225}
226
227float QSSGRenderCamera::verticalFov(const QRectF &inViewport) const
228{
229 return verticalFov(getAspectRatio(inViewport));
230}
231
233{
234 cameraDirtyFlags |= FlagT(dirtyFlag);
236}
237
239{
240 cameraDirtyFlags &= ~FlagT(dirtyFlag);
242}
243
244static float getZNear(const QMatrix4x4 &projection)
245{
246 const float *data = projection.constData();
247 QSSGPlane plane(QVector3D(data[3] + data[2], data[7] + data[6], data[11] + data[10]), -data[15] - data[14]);
248 plane.normalize();
249 return plane.d;
250}
251
252static QVector2D getViewportHalfExtents(const QMatrix4x4 &projection) {
253 const float *data = projection.constData();
254
255 QSSGPlane nearPlane(QVector3D(data[3] + data[2], data[7] + data[6], data[11] + data[10]), -data[15] - data[14]);
256 nearPlane.normalize();
257 QSSGPlane rightPlane(QVector3D(data[3] - data[0], data[7] - data[4], data[11] - data[8]), -data[15] + data[12]);
258 rightPlane.normalize();
259 QSSGPlane topPlane(QVector3D(data[3] - data[1], data[7] - data[5], data[11] - data[9]), -data[15] + data[13]);
260 topPlane.normalize();
261
262 // Get intersection the 3 planes
263 float denom = QVector3D::dotProduct(QVector3D::crossProduct(nearPlane.n, rightPlane.n), topPlane.n);
264 if (qFuzzyIsNull(denom))
265 return QVector2D();
266
267 QVector3D intersection = (QVector3D::crossProduct(rightPlane.n, topPlane.n) * nearPlane.d +
268 (QVector3D::crossProduct(topPlane.n, nearPlane.n) * rightPlane.d) +
269 (QVector3D::crossProduct(nearPlane.n, rightPlane.n) * topPlane.d)) / denom;
270
271 return QVector2D(intersection.x(), intersection.y());
272}
273
275{
276 if (type == QSSGRenderGraphObject::Type::OrthographicCamera)
278
279 float zn = getZNear(projection);
280 float width = getViewportHalfExtents(projection).x() * 2.0;
281 return 1.0 / (zn / width);
282
283}
284
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
void frustum(float left, float right, float bottom, float top, float nearPlane, float farPlane)
Multiplies this matrix by another that applies a perspective frustum projection for a window with low...
QVector4D column(int index) const
Returns the elements of column index as a 4D vector.
Definition qmatrix4x4.h:259
void ortho(const QRect &rect)
This is an overloaded member function, provided for convenience. It differs from the above function o...
float * data()
Returns a pointer to the raw data of this matrix.
void setColumn(int index, const QVector4D &value)
Sets the elements of column index to the components of value.
Definition qmatrix4x4.h:265
void perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane)
Multiplies this matrix by another that applies a perspective projection.
QMatrix4x4 inverted(bool *invertible=nullptr) const
Returns the inverse of this matrix.
void setToIdentity()
Sets this matrix to the identity.
Definition qmatrix4x4.h:316
const float * constData() const
Returns a constant pointer to the raw data of this matrix.
Definition qmatrix4x4.h:147
The QQuaternion class represents a quaternion consisting of a vector and scalar.
Definition qquaternion.h:21
static QQuaternion fromAxisAndAngle(const QVector3D &axis, float angle)
Creates a normalized quaternion that corresponds to rotating through angle degrees about the specifie...
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
Representation of a plane.
Definition qssgplane_p.h:31
float d
The distance from the origin.
Definition qssgplane_p.h:83
void normalize()
equivalent plane with unit normal
Definition qssgplane.cpp:16
QVector3D n
The normal to the plane.
Definition qssgplane_p.h:82
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:502
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:501
constexpr void setY(float y) noexcept
Sets the y coordinate of this point to the given finite y coordinate.
Definition qvectornd.h:505
constexpr void setX(float x) noexcept
Sets the x coordinate of this point to the given finite x coordinate.
Definition qvectornd.h:504
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
constexpr void setX(float x) noexcept
Sets the x coordinate of this point to the given finite x coordinate.
Definition qvectornd.h:674
QVector3D normalized() const noexcept
Returns the normalized unit vector form of this vector.
Definition qvectornd.h:695
constexpr float lengthSquared() const noexcept
Returns the squared length of the vector from the origin.
Definition qvectornd.h:713
constexpr void setY(float y) noexcept
Sets the y coordinate of this point to the given finite y coordinate.
Definition qvectornd.h:675
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:671
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:670
constexpr void setZ(float z) noexcept
Sets the z coordinate of this point to the given finite z coordinate.
Definition qvectornd.h:676
static constexpr float dotProduct(QVector3D v1, QVector3D v2) noexcept
Returns the dot product of v1 and v2.
Definition qvectornd.h:770
static constexpr QVector3D crossProduct(QVector3D v1, QVector3D v2) noexcept
Returns the cross-product of vectors v1 and v2, which is normal to the plane spanned by v1 and v2.
Definition qvectornd.h:775
void normalize() noexcept
Normalizes the current vector in place.
Definition qvectornd.h:702
The QVector4D class represents a vector or vertex in 4D space.
Definition qvectornd.h:330
QVector4D normalized() const noexcept
Returns the normalized unit vector form of this vector.
Definition qvectornd.h:910
Combined button and popup list for selecting options.
float getAspectRatio(const QRectF &inViewport)
constexpr Initialization Uninitialized
QVector3D Q_QUICK3DUTILS_EXPORT transform(const QMatrix3x3 &m, const QVector3D &v)
Definition qssgutils.cpp:43
QVector3D Q_QUICK3DUTILS_EXPORT transform(const QMatrix4x4 &m, const QVector3D &v)
Definition qssgutils.cpp:86
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
#define qWarning
Definition qlogging.h:162
constexpr float qRadiansToDegrees(float radians)
Definition qmath.h:281
auto qAcos(T v)
Definition qmath.h:72
auto qAtan(T v)
Definition qmath.h:84
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
auto qTan(T v)
Definition qmath.h:66
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLint GLsizei width
GLint left
GLenum type
GLint GLint bottom
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
static qreal dot(const QPointF &a, const QPointF &b)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QVector2D relativeToNormalizedCoordinates(const QRectF &r, QVector2D rectRelativeCoords)
static QVector2D getViewportHalfExtents(const QMatrix4x4 &projection)
static float getZNear(const QMatrix4x4 &projection)
static QQuaternion rotationQuaternionForLookAt(const QVector3D &sourcePosition, const QVector3D &sourceDirection, const QVector3D &targetPosition, const QVector3D &upDirection)
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
void clearDirty(DirtyFlag dirtyFlag)
std::underlying_type_t< DirtyFlag > FlagT
float getOrthographicScaleFactor(const QRectF &inViewport) const
bool computeFrustumOrtho(const QRectF &inViewport)
float getLevelOfDetailMultiplier() const
void calculateViewProjectionMatrix(QMatrix4x4 &outMatrix) const
float verticalFov(float aspectRatio) const
bool computeFrustumPerspective(const QRectF &inViewport)
bool computeCustomFrustum(const QRectF &inViewport)
void calculateViewProjectionWithoutTranslation(float near, float far, QMatrix4x4 &outMatrix) const
bool isDirty(DirtyFlag dirtyFlag=DirtyMask) const
void lookAt(const QVector3D &inCameraPos, const QVector3D &inUpDir, const QVector3D &inTargetPos, const QVector3D &pivot)
QSSGRenderRay unproject(const QVector2D &inLayerRelativeMouseCoords, const QRectF &inViewport) const
QVector3D unprojectToPosition(const QVector3D &inGlobalPos, const QSSGRenderRay &inRay) const
void markDirty(DirtyFlag dirtyFlag)
bool calculateProjection(const QRectF &inViewport)
QSSGRenderCamera(QSSGRenderGraphObject::Type type)
static Q_REQUIRED_RESULT constexpr bool isCamera(Type type) Q_DECL_NOTHROW
static constexpr QVector3D initScale
bool calculateGlobalVariables()
void clearDirty(DirtyFlag dirtyFlag)
QVector3D getDirection() const
QMatrix4x4 globalTransform
QVector3D getScalingCorrectDirection() const
static QMatrix4x4 calculateTransformMatrix(QVector3D position, QVector3D scale, QVector3D pivot, QQuaternion rotation)
QMatrix4x4 localTransform
QMatrix3x3 calculateNormalMatrix() const
void markDirty(DirtyFlag dirtyFlag)
static std::optional< QVector3D > intersect(const QSSGPlane &inPlane, const QSSGRenderRay &ray)
QVector3D direction