38bool QSSGRenderCamera::calculateProjection(
const QRectF &inViewport, Configuration config)
47 const bool argumentsChanged = inViewport != previousInViewport;
48 if (!argumentsChanged && !isDirty(DirtyFlag::CameraDirty))
50 previousInViewport = inViewport;
51 clearDirty(DirtyFlag::CameraDirty);
54 case QSSGRenderGraphObject::Type::OrthographicCamera:
55 retval = computeFrustumOrtho(inViewport, clipPlanes, magnification, config, projection);
57 case QSSGRenderGraphObject::Type::PerspectiveCamera:
58 retval = computeFrustumPerspective(inViewport, fov, clipPlanes, projection);
60 case QSSGRenderGraphObject::Type::CustomCamera:
63 case QSSGRenderGraphObject::Type::CustomFrustumCamera:
64 retval = computeCustomFrustum(customFrustum, clipPlanes, projection);
71 float *writePtr(projection.data());
72 frustumScale.setX(writePtr[0]);
73 frustumScale.setY(writePtr[5]);
83bool QSSGRenderCamera::computeFrustumPerspective(QRectF inViewport,
84 QSSGRenderCamera::FieldOfView fov,
85 QSSGRenderCamera::ClipPlanes clipPlane,
86 QMatrix4x4 &outProjection)
88 outProjection.setToIdentity();
89 const float aspectRatio = getAspectRatio(inViewport);
90 const auto vfov = fov.asVerticalFov(aspectRatio);
91 outProjection.perspective(vfov.degrees(), aspectRatio, clipPlane.clipNear(), clipPlane.clipFar());
95bool QSSGRenderCamera::computeCustomFrustum(QSSGRenderCamera::Frustum frustum,
96 QSSGRenderCamera::ClipPlanes clipPlanes,
97 QMatrix4x4 &outProjection)
99 outProjection.setToIdentity();
100 outProjection.frustum(frustum.left, frustum.right, frustum.bottom, frustum.top, clipPlanes.clipNear(), clipPlanes.clipFar());
104void QSSGRenderCamera::calculateViewProjectionMatrix(
const QMatrix4x4 &globalTransform,
105 const QMatrix4x4 &projection,
106 QMatrix4x4 &outMatrix)
108 QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
109 nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
110 nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
111 nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
112 nonScaledGlobal.setColumn(3, globalTransform.column(3));
113 outMatrix = projection * nonScaledGlobal.inverted();
121bool QSSGRenderCamera::computeFrustumOrtho(QRectF inViewport,
122 QSSGRenderCamera::ClipPlanes clipPlanes,
123 QSSGRenderCamera::Magnification magnification,
124 Configuration config,
125 QMatrix4x4 &outProjection)
129 outProjection.setToIdentity();
135 magnification *= config.ssaaMultiplier;
136 const float halfWidth = inViewport.width() / 2.0f / magnification.horizontal() / config.dpr;
137 const float halfHeight = inViewport.height() / 2.0f / magnification.vertical() / config.dpr;
138 outProjection.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, clipPlanes.clipNear(), clipPlanes.clipFar());
143 const QVector3D &sourceDirection,
144 const QVector3D &targetPosition,
145 const QVector3D &upDirection)
147 QVector3D targetDirection = sourcePosition - targetPosition;
148 targetDirection.normalize();
150 QVector3D rotationAxis = QVector3D::crossProduct(sourceDirection, targetDirection);
152 const QVector3D normalizedAxis = rotationAxis.normalized();
153 if (qFuzzyIsNull(normalizedAxis.lengthSquared()))
154 rotationAxis = upDirection;
156 float dot = QVector3D::dotProduct(sourceDirection, targetDirection);
157 float rotationAngle =
float(qRadiansToDegrees(qAcos(qreal(dot))));
159 return QQuaternion::fromAxisAndAngle(rotationAxis, rotationAngle);
162void QSSGRenderCamera::lookAt(
const QVector3D &inCameraPos,
const QVector3D &inUpDir,
const QVector3D &inTargetPos,
const QVector3D &pivot)
164 QQuaternion rotation = rotationQuaternionForLookAt(inCameraPos, getScalingCorrectDirection(localTransform), inTargetPos, inUpDir.normalized());
165 localTransform = QSSGRenderNode::calculateTransformMatrix(inCameraPos, QSSGRenderNode::initScale, pivot, rotation);
166 QSSGRenderNode::markDirty(QSSGRenderNode::DirtyFlag::TransformDirty);
169void QSSGRenderCamera::calculateViewProjectionMatrix(
const QMatrix4x4 &globalTransform, QMatrix4x4 &outMatrix)
const
171 QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
172 nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
173 nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
174 nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
175 nonScaledGlobal.setColumn(3, globalTransform.column(3));
176 outMatrix = projection * nonScaledGlobal.inverted();
179void QSSGRenderCamera::calculateViewProjectionWithoutTranslation(
const QMatrix4x4 &globalTransform,
float clipNear,
float clipFar, QMatrix4x4 &outMatrix)
const
181 if (qFuzzyIsNull(clipFar - clipNear)) {
182 qWarning() <<
"QSSGRenderCamera::calculateViewProjection: far == near";
186 QMatrix4x4 proj = projection;
187 proj(2, 2) = -(clipFar + clipNear) / (clipFar - clipNear);
188 proj(2, 3) = -2 * clipFar * clipNear / (clipFar - clipNear);
189 QMatrix4x4 nonScaledGlobal(Qt::Uninitialized);
190 nonScaledGlobal.setColumn(0, globalTransform.column(0).normalized());
191 nonScaledGlobal.setColumn(1, globalTransform.column(1).normalized());
192 nonScaledGlobal.setColumn(2, globalTransform.column(2).normalized());
193 nonScaledGlobal.setColumn(3, QVector4D(0, 0, 0, 1));
194 outMatrix = proj * nonScaledGlobal.inverted();
197QSSGRenderRay QSSGRenderCamera::unproject(
const QMatrix4x4 &globalTransform,
198 const QVector2D &inViewportRelativeCoords,
199 const QRectF &inViewport)
const
201 QSSGRenderRay theRay;
202 QVector2D normalizedCoords = QSSGUtils::rect::relativeToNormalizedCoordinates(inViewport, inViewportRelativeCoords);
203 QVector3D &outOrigin(theRay.origin);
204 QVector3D &outDir(theRay.direction);
205 QVector2D inverseFrustumScale(1.0f / frustumScale.x(), 1.0f / frustumScale.y());
206 QVector2D scaledCoords(inverseFrustumScale.x() * normalizedCoords.x(), inverseFrustumScale.y() * normalizedCoords.y());
208 if (type == QSSGRenderCamera::Type::OrthographicCamera) {
209 outOrigin.setX(scaledCoords.x());
210 outOrigin.setY(scaledCoords.y());
211 outOrigin.setZ(0.0f);
217 outOrigin.setX(0.0f);
218 outOrigin.setY(0.0f);
219 outOrigin.setZ(0.0f);
221 outDir.setX(scaledCoords.x());
222 outDir.setY(scaledCoords.y());
226 outOrigin = QSSGUtils::mat44::transform(globalTransform, outOrigin);
227 QMatrix3x3 theNormalMatrix = globalTransform.normalMatrix();
229 outDir = QSSGUtils::mat33::transform(theNormalMatrix, outDir);
256 const float *data = projection.constData();
258 QSSGPlane nearPlane(QVector3D(data[3] + data[2], data[7] + data[6], data[11] + data[10]), -data[15] - data[14]);
259 nearPlane.normalize();
260 QSSGPlane rightPlane(QVector3D(data[3] - data[0], data[7] - data[4], data[11] - data[8]), -data[15] + data[12]);
261 rightPlane.normalize();
262 QSSGPlane topPlane(QVector3D(data[3] - data[1], data[7] - data[5], data[11] - data[9]), -data[15] + data[13]);
263 topPlane.normalize();
266 float denom = QVector3D::dotProduct(QVector3D::crossProduct(nearPlane.n, rightPlane.n), topPlane.n);
267 if (qFuzzyIsNull(denom))
270 QVector3D intersection = (QVector3D::crossProduct(rightPlane.n, topPlane.n) * nearPlane.d +
271 (QVector3D::crossProduct(topPlane.n, nearPlane.n) * rightPlane.d) +
272 (QVector3D::crossProduct(nearPlane.n, rightPlane.n) * topPlane.d)) / denom;
274 return QVector2D(intersection.x(), intersection.y());
277float QSSGRenderCamera::getLevelOfDetailMultiplier()
const
279 if (type == QSSGRenderGraphObject::Type::OrthographicCamera)
280 return getViewportHalfExtents(projection).x();
282 float zn = getZNear(projection);
283 float width = getViewportHalfExtents(projection).x() * 2.0;
284 return 1.0 / (zn / width);