114void QQuick3DCamera::setLookAtNode(QQuick3DNode *node)
116 if (m_lookAtNode == node)
120 disconnect(m_lookAtNode, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
121 disconnect(
this, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
127 connect(m_lookAtNode, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
128 connect(
this, &QQuick3DNode::scenePositionChanged,
this, &QQuick3DCamera::updateLookAt);
131 emit lookAtNodeChanged();
150QVector3D QQuick3DCamera::mapToViewport(
const QVector3D &scenePos)
const
152 QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(
this)->spatialNode);
154 return QVector3D(0, 0, 0);
156 QVector4D scenePosRightHand(scenePos, 1);
159 const QMatrix4x4 sceneToCamera = sceneTransform().inverted();
160 const QMatrix4x4 projectionViewMatrix = cameraNode->projection * sceneToCamera;
161 const QVector4D transformedScenePos = QSSGUtils::mat44::transform(projectionViewMatrix, scenePosRightHand);
163 if (qFuzzyIsNull(transformedScenePos.w()) || qIsNaN(transformedScenePos.w()))
164 return QVector3D(0, 0, 0);
167 QVector3D scenePosView = transformedScenePos.toVector3D() / transformedScenePos.w();
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;
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();
186 const float distanceToScenePos = scenePosVec.length()
187 * (QVector3D::dotProduct(direction, scenePosVec) > 0.f ? 1 : -1);
189 scenePosView.setZ(distanceToScenePos);
192 scenePosView.setX((scenePosView.x() / 2) + 0.5f);
193 scenePosView.setY((scenePosView.y() / 2) + 0.5f);
195 scenePosView.setY(1 - scenePosView.y());
213QVector3D QQuick3DCamera::mapFromViewport(
const QVector3D &viewportPos)
const
215 QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(
this)->spatialNode);
217 return QVector3D(0, 0, 0);
220 QVector4D clipNearPos(viewportPos, 1);
222 clipNearPos.setY(1 - clipNearPos.y());
224 clipNearPos.setX((clipNearPos.x() * 2.0f) - 1.0f);
225 clipNearPos.setY((clipNearPos.y() * 2.0f) - 1.0f);
226 QVector4D clipFarPos = clipNearPos;
229 clipNearPos.setZ(-1);
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);
238 if (qFuzzyIsNull(transformedClipNearPos.w()) || qIsNaN(transformedClipNearPos.w()) ||
239 qFuzzyIsNull(transformedClipFarPos.w()) || qIsNaN(transformedClipFarPos.w()))
240 return QVector3D(0, 0, 0);
243 const QVector3D clipNearPosScene = transformedClipNearPos.toVector3D()
244 / transformedClipNearPos.w();
245 const QVector3D clipFarPosScene = transformedClipFarPos.toVector3D()
246 / transformedClipFarPos.w();
249 const QVector3D direction = (clipFarPosScene - clipNearPosScene).normalized();
250 const float distanceFromClipNear = viewportPos.z();
251 QVector3D scenePos = clipNearPosScene + (direction * distanceFromClipNear);
259QVector3D QQuick3DCamera::mapToViewport(
const QVector3D &scenePos,
264 if (QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(updateSpatialNode(QQuick3DObjectPrivate::get(
this)->spatialNode))) {
265 QQuick3DObjectPrivate::get(
this)->spatialNode = cameraNode;
266 QSSGRenderCamera::Configuration camConfig { cameraNode->getDpr(), 1.0f };
267 QSSGRenderCamera::calculateProjectionInternal(*cameraNode, QRect(0, 0, width * camConfig.dpr, height * camConfig.dpr), camConfig);
270 return QQuick3DCamera::mapToViewport(scenePos);
276QVector3D QQuick3DCamera::mapFromViewport(
const QVector3D &viewportPos,
281 if (QSSGRenderCamera *cameraNode =
static_cast<QSSGRenderCamera *>(updateSpatialNode(QQuick3DObjectPrivate::get(
this)->spatialNode))) {
282 QQuick3DObjectPrivate::get(
this)->spatialNode = cameraNode;
283 QSSGRenderCamera::Configuration camConfig { cameraNode->getDpr(), 1.0f };
284 QSSGRenderCamera::calculateProjectionInternal(*cameraNode, QRect(0, 0, width * camConfig.dpr, height * camConfig.dpr));
287 return QQuick3DCamera::mapFromViewport(viewportPos);
297void QQuick3DCamera::lookAt(
const QVector3D &scenePos)
302 const auto &targetPosition = scenePos;
303 auto sourcePosition = scenePosition();
305 QVector3D targetVector = sourcePosition - targetPosition;
307 float yaw = qRadiansToDegrees(atan2(targetVector.x(), targetVector.z()));
309 QVector2D p(targetVector.x(), targetVector.z());
310 float pitch = qRadiansToDegrees(atan2(p.length(), targetVector.y())) - 90;
312 const float previousRoll = eulerRotation().z();
313 setEulerRotation(QVector3D(pitch, yaw, previousRoll));
340QSSGRenderGraphObject *QQuick3DCamera::updateSpatialNode(QSSGRenderGraphObject *node)
344 node =
new QSSGRenderCamera(QQuick3DObjectPrivate::get(
this)->type);
347 QQuick3DNode::updateSpatialNode(node);
349 QSSGRenderCamera *camera =
static_cast<QSSGRenderCamera *>(node);
350 if (qUpdateIfNeeded(camera->enableFrustumClipping, m_frustumCullingEnabled))
351 camera->markDirty(QSSGRenderCamera::DirtyFlag::CameraDirty);
352 if (qUpdateIfNeeded(camera->levelOfDetailPixelThreshold, m_levelOfDetailBias))
353 camera->markDirty(QSSGRenderCamera::DirtyFlag::CameraDirty);
354 if (qUpdateIfNeeded(camera->layerMask, quint32(QQuick3DNodePrivate::get(
this)->m_tag)))
355 camera->markDirty(QSSGRenderCamera::DirtyFlag::LayerMaskDirty);