From 5a49c1669437ef2d4e1c2e284c912cb774495999 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 22 Mar 2024 17:45:21 +0200 Subject: [PATCH] QmlDesigner: Use space key to move close to object at crosshairs When in fly mode in 3D view, crosshairs are shown in the middle of the active split. Pressing space in fly mode when there is a model at the crosshairs will move the camera close to the model. Fixes: QDS-12292 Change-Id: Id15c13458af3763f4e0712614cf9cf3ed695fb5d Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- src/tools/qml2puppet/editor3d_qt6.qrc | 2 + .../qml2puppet/mockfiles/images/crosshair.png | Bin 0 -> 172 bytes .../mockfiles/images/crosshair@2x.png | Bin 0 -> 202 bytes .../mockfiles/qt6/EditCameraController.qml | 29 ++++++++++- .../qml2puppet/editor3d/generalhelper.cpp | 49 ++++++++++++++++++ .../qml2puppet/editor3d/generalhelper.h | 2 + 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/tools/qml2puppet/mockfiles/images/crosshair.png create mode 100644 src/tools/qml2puppet/mockfiles/images/crosshair@2x.png diff --git a/src/tools/qml2puppet/editor3d_qt6.qrc b/src/tools/qml2puppet/editor3d_qt6.qrc index 2913fbe15e0..d76b1941b99 100644 --- a/src/tools/qml2puppet/editor3d_qt6.qrc +++ b/src/tools/qml2puppet/editor3d_qt6.qrc @@ -8,6 +8,8 @@ mockfiles/images/editor_camera@2x.png mockfiles/images/editor_particlesystem.png mockfiles/images/editor_particlesystem@2x.png + mockfiles/images/crosshair.png + mockfiles/images/crosshair@2x.png mockfiles/images/directional.png mockfiles/images/directional@2x.png mockfiles/images/point.png diff --git a/src/tools/qml2puppet/mockfiles/images/crosshair.png b/src/tools/qml2puppet/mockfiles/images/crosshair.png new file mode 100644 index 0000000000000000000000000000000000000000..6c302635132c09f675b8fc177096802a7c86aa3a GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-7G?$phNU`BwlFX-hz9tCxH2#>D9bBA(EPb` z*REdu|NsADHM2Ji3=GUAL4Lsu3g=Ta?PD1j7@R#_978NlCnq>Cs426(akwGb&Qkno z1jG=J{g zwX0YE|Np;O&Fl>W0|RqOkY6x^!ub?U`&b4BhD1*n$B>A_$q5Jerie;-F!iXhEy+wU zkiKfLDlz2ninfL84o(T-T{3O$;slW%rdtfD$tex0$wmt`43Z3dotZQvHtj2r*u<57 zDOZAZae~MNh1LCKnQo>%SrS(bRyEeeN-?OU>fBLDVNYRTU|{fc^>bP0l+XkK7L7iS literal 0 HcmV?d00001 diff --git a/src/tools/qml2puppet/mockfiles/qt6/EditCameraController.qml b/src/tools/qml2puppet/mockfiles/qt6/EditCameraController.qml index 2d77aaf9877..255d93e5295 100644 --- a/src/tools/qml2puppet/mockfiles/qt6/EditCameraController.qml +++ b/src/tools/qml2puppet/mockfiles/qt6/EditCameraController.qml @@ -102,6 +102,23 @@ Item { storeCameraState(0); } + function approachObject() + { + if (!camera) + return; + + var pickResult = _generalHelper.pickViewAt(view3d, width / 2, height / 2); + var resolvedResult = _generalHelper.resolvePick(pickResult.objectHit); + + if (resolvedResult) { + var newLookAtAndZoom = _generalHelper.approachNode(camera, _defaultCameraLookAtDistance, + resolvedResult, view3D); + _lookAtPoint = newLookAtAndZoom.toVector3d(); + _zoomFactor = newLookAtAndZoom.w; + storeCameraState(0); + } + } + function jumpToRotation(rotation) { let distance = camera.scenePosition.minus(_lookAtPoint).length() @@ -240,6 +257,13 @@ Item { } } + Image { + anchors.centerIn: parent + source: "qrc:///qtquickplugin/mockfiles/images/crosshair.png" + visible: cameraCtrl.flyMode && viewRoot.activeSplit === cameraCtrl.splitId + opacity: 0.7 + } + MouseArea { id: mouseHandler acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton @@ -304,7 +328,10 @@ Item { Keys.onPressed: (event) => { event.accepted = true; - _generalHelper.startCameraMove(cameraCtrl.camera, cameraCtrl.getMoveVectorForKey(event.key)); + if (cameraCtrl.flyMode && event.key === Qt.Key_Space) + approachObject(); + else + _generalHelper.startCameraMove(cameraCtrl.camera, cameraCtrl.getMoveVectorForKey(event.key)); } Keys.onReleased: (event) => { diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp index b33a480a450..dadd8176330 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp @@ -398,6 +398,55 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul return QVector4D(lookAt, cameraZoomFactor); } +// Approaches the specified node without changing camera orientation +QVector4D GeneralHelper::approachNode( + QQuick3DCamera *camera, float defaultLookAtDistance, QObject *node, + QQuick3DViewport *viewPort) +{ + auto node3d = qobject_cast(node); + if (!camera || !node3d) + return QVector4D(0.f, 0.f, 0.f, 1.f); + + QVector3D minBounds = maxVec; + QVector3D maxBounds = minVec; + + getBounds(viewPort, node3d, minBounds, maxBounds); // Bounds are in node3d local coordinates + + QVector3D extents = maxBounds - minBounds; + QVector3D focusLookAt = minBounds + (extents / 2.f); + + if (node3d->parentNode()) { + QMatrix4x4 m = node3d->parentNode()->sceneTransform(); + focusLookAt = m.map(focusLookAt); + } + + float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x()) + + qreal(extents.y()) * qreal(extents.y()) + + qreal(extents.z()) * qreal(extents.z())); + + // Reset camera position to default zoom + QMatrix4x4 m = camera->sceneTransform(); + const float *dataPtr(m.data()); + QVector3D newLookVector(dataPtr[8], dataPtr[9], dataPtr[10]); + newLookVector.normalize(); + + // We don't want to change camera orientation, so calculate projection point on current + // camera look vector + QVector3D focusLookAtVector = focusLookAt - camera->position(); + float dot = QVector3D::dotProduct(newLookVector, focusLookAtVector); + QVector3D newLookAt = camera->position() + dot * newLookVector; + + newLookVector *= defaultLookAtDistance; + camera->setPosition(newLookAt + newLookVector); + + float divisor = 1050.f; + float newZoomFactor = qBound(.01f, maxExtent / divisor, 100.f); + float cameraZoomFactor = zoomCamera(viewPort, camera, 0, defaultLookAtDistance, newLookAt, + newZoomFactor, false); + + return QVector4D(newLookAt, cameraZoomFactor); +} + // This function can be used to synchronously focus camera on a node, which doesn't have to be // a selection box for bound calculations to work. This is used to focus the view for // various preview image generations, where doing things asynchronously is not good diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h index 5622918a64b..62a95d86a6f 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h @@ -70,6 +70,8 @@ public: const QVariant &nodes, QQuick3DViewport *viewPort, float oldZoom, bool updateZoom = true, bool closeUp = false); + Q_INVOKABLE QVector4D approachNode(QQuick3DCamera *camera, float defaultLookAtDistance, + QObject *node, QQuick3DViewport *viewPort); Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, float defaultLookAtDistance, bool closeUp);