118void QQuick3DCamera::setLookAtNode(QQuick3DNode *node)
120 if (m_lookAtNode == node)
124 disconnect(m_lookAtNode, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
125 disconnect(
this, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
131 connect(m_lookAtNode, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
132 connect(
this, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
135 emit lookAtNodeChanged();
154QVector3D QQuick3DCamera::mapToViewport(
const QVector3D &scenePos)
const
156 QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(
this)->spatialNode);
158 return QVector3D(0, 0, 0);
160 QVector4D scenePosRightHand(scenePos, 1);
163 const QMatrix4x4 sceneToCamera = sceneTransform().inverted();
164 const QMatrix4x4 projectionViewMatrix = cameraNode->projection * sceneToCamera;
165 const QVector4D transformedScenePos = QSSGUtils::mat44::transform(projectionViewMatrix, scenePosRightHand);
167 if (qFuzzyIsNull(transformedScenePos.w()) || qIsNaN(transformedScenePos.w()))
168 return QVector3D(0, 0, 0);
171 QVector3D scenePosView = transformedScenePos.toVector3D() / transformedScenePos.w();
175 const QVector4D clipNearPos(scenePosView.x(), scenePosView.y(), -1, 1);
176 auto invProj = projectionViewMatrix.inverted();
177 const QVector4D clipNearPosTransformed = QSSGUtils::mat44::transform(invProj, clipNearPos);
178 if (qFuzzyIsNull(clipNearPosTransformed.w()) || qIsNaN(clipNearPosTransformed.w()))
179 return QVector3D(0, 0, 0);
180 const QVector4D clipNearPosScene = clipNearPosTransformed / clipNearPosTransformed.w();
181 QVector4D clipFarPos = clipNearPos;
183 const QVector4D clipFarPosTransformed = QSSGUtils::mat44::transform(invProj, clipFarPos);
184 if (qFuzzyIsNull(clipFarPosTransformed.w()) || qIsNaN(clipFarPosTransformed.w()))
185 return QVector3D(0, 0, 0);
186 const QVector4D clipFarPosScene = clipFarPosTransformed / clipFarPosTransformed.w();
187 const QVector3D direction = (clipFarPosScene - clipNearPosScene).toVector3D();
188 const QVector3D scenePosVec = (scenePosRightHand - clipNearPosScene).toVector3D();
190 const float distanceToScenePos = scenePosVec.length()
191 * (QVector3D::dotProduct(direction, scenePosVec) > 0.f ? 1 : -1);
193 scenePosView.setZ(distanceToScenePos);
196 scenePosView.setX((scenePosView.x() / 2) + 0.5f);
197 scenePosView.setY((scenePosView.y() / 2) + 0.5f);
199 scenePosView.setY(1 - scenePosView.y());
217QVector3D QQuick3DCamera::mapFromViewport(
const QVector3D &viewportPos)
const
219 QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(
this)->spatialNode);
221 return QVector3D(0, 0, 0);
224 QVector4D clipNearPos(viewportPos, 1);
226 clipNearPos.setY(1 - clipNearPos.y());
228 clipNearPos.setX((clipNearPos.x() * 2.0f) - 1.0f);
229 clipNearPos.setY((clipNearPos.y() * 2.0f) - 1.0f);
230 QVector4D clipFarPos = clipNearPos;
233 clipNearPos.setZ(-1);
237 const QMatrix4x4 sceneToCamera = sceneTransform().inverted();
238 const QMatrix4x4 projectionViewMatrixInv = (cameraNode->projection * sceneToCamera).inverted();
239 const QVector4D transformedClipNearPos = QSSGUtils::mat44::transform(projectionViewMatrixInv, clipNearPos);
240 const QVector4D transformedClipFarPos = QSSGUtils::mat44::transform(projectionViewMatrixInv, clipFarPos);
242 if (qFuzzyIsNull(transformedClipNearPos.w()) || qIsNaN(transformedClipNearPos.w()) ||
243 qFuzzyIsNull(transformedClipFarPos.w()) || qIsNaN(transformedClipFarPos.w()))
244 return QVector3D(0, 0, 0);
247 const QVector3D clipNearPosScene = transformedClipNearPos.toVector3D()
248 / transformedClipNearPos.w();
249 const QVector3D clipFarPosScene = transformedClipFarPos.toVector3D()
250 / transformedClipFarPos.w();
253 const QVector3D direction = (clipFarPosScene - clipNearPosScene).normalized();
254 const float distanceFromClipNear = viewportPos.z();
255 QVector3D scenePos = clipNearPosScene + (direction * distanceFromClipNear);
263QVector3D QQuick3DCamera::mapToViewport(
const QVector3D &scenePos,
268 if (QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(updateSpatialNode(QQuick3DObjectPrivate::get(
this)->spatialNode))) {
269 QQuick3DObjectPrivate::get(
this)->spatialNode = cameraNode;
270 QSSGRenderCamera::Configuration camConfig { cameraNode->getDpr(), 1.0f };
271 QSSGRenderCamera::calculateProjectionInternal(*cameraNode, QRect(0, 0, width * camConfig.dpr, height * camConfig.dpr), camConfig);
274 return QQuick3DCamera::mapToViewport(scenePos);
280QVector3D QQuick3DCamera::mapFromViewport(
const QVector3D &viewportPos,
285 if (QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(updateSpatialNode(QQuick3DObjectPrivate::get(
this)->spatialNode))) {
286 QQuick3DObjectPrivate::get(
this)->spatialNode = cameraNode;
287 QSSGRenderCamera::Configuration camConfig { cameraNode->getDpr(), 1.0f };
288 QSSGRenderCamera::calculateProjectionInternal(*cameraNode, QRect(0, 0, width * camConfig.dpr, height * camConfig.dpr));
291 return QQuick3DCamera::mapFromViewport(viewportPos);
301void QQuick3DCamera::lookAt(
const QVector3D &scenePos)
306 const auto &targetPosition = scenePos;
307 auto sourcePosition = scenePosition();
309 QVector3D targetVector = sourcePosition - targetPosition;
311 float yaw = qRadiansToDegrees(atan2(targetVector.x(), targetVector.z()));
313 QVector2D p(targetVector.x(), targetVector.z());
314 float pitch = qRadiansToDegrees(atan2(p.length(), targetVector.y())) - 90;
316 const float previousRoll = eulerRotation().z();
317 setEulerRotation(QVector3D(pitch, yaw, previousRoll));
344QSSGRenderGraphObject *QQuick3DCamera::updateSpatialNode(QSSGRenderGraphObject *node)
348 node =
new QSSGRenderCamera(QQuick3DObjectPrivate::get(
this)->type);
351 QQuick3DNode::updateSpatialNode(node);
353 QSSGRenderCamera *camera =
static_cast<QSSGRenderCamera *>(node);
354 if (qUpdateIfNeeded(camera->enableFrustumClipping, m_frustumCullingEnabled))
355 camera->markDirty(QSSGRenderCamera::DirtyFlag::CameraDirty);
356 if (qUpdateIfNeeded(camera->levelOfDetailPixelThreshold, m_levelOfDetailBias))
357 camera->markDirty(QSSGRenderCamera::DirtyFlag::CameraDirty);
358 if (qUpdateIfNeeded(camera->layerMask, quint32(QQuick3DNodePrivate::get(
this)->m_tag)))
359 camera->markDirty(QSSGRenderCamera::DirtyFlag::LayerMaskDirty);