summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-11-20 18:01:34 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-11-22 13:57:43 +0000
commitc7120bde92d1ad3402fb8a093187e6b752da244f (patch)
tree47eb55c3198d4d5e8a2e6508754e0368560eafec
parentb619c60ff715c99a3bee64e14ae41600028df48e (diff)
downloadqt-creator-c7120bde92d1ad3402fb8a093187e6b752da244f.tar.gz
QmlDesigner: Implement axis helper on 3D edit view
Axis helper shows up on top right corner of 3D edit view. Clicking on axis helper arms zooms camera on that side of the selected object. Change-Id: Ibd81a933036f7965f825e3dc97ad7156da62e14c Fixes: QDS-1205 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml1
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml133
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml70
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml10
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml17
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml2
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml7
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.meshbin0 -> 158516 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp59
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h4
-rw-r--r--share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc3
11 files changed, 297 insertions, 9 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml
index cec64b32b5..dc4c38d100 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml
@@ -81,6 +81,7 @@ Node {
MouseArea3D {
id: helper
+ active: false
view3D: overlayNode.view3D
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
new file mode 100644
index 0000000000..86c60db721
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick3D 1.0
+
+View3D {
+ id: axisHelperView
+
+ property var editCameraCtrl
+ property Node selectedNode
+
+ camera: axisHelperCamera
+
+ Node {
+ OrthographicCamera {
+ id: axisHelperCamera
+ rotation: editCameraCtrl.camera.rotation
+ position: editCameraCtrl.camera.position.minus(editCameraCtrl._lookAtPoint)
+ .normalized().times(600)
+ }
+
+ AutoScaleHelper {
+ id: autoScale
+ view3D: axisHelperView
+ position: axisHelperGizmo.scenePosition
+ }
+
+ Node {
+ id: axisHelperGizmo
+ scale: autoScale.getScale(Qt.vector3d(4, 4, 4))
+
+ AxisHelperArm {
+ id: armX
+ rotation: Qt.vector3d(0, 0, -90)
+ color: Qt.rgba(1, 0, 0, 1)
+ hoverColor: Qt.lighter(Qt.rgba(1, 0, 0, 1))
+ view3D: axisHelperView
+ camRotPos: Qt.vector3d(0, 90, 0)
+ camRotNeg: Qt.vector3d(0, -90, 0)
+ }
+
+ AxisHelperArm {
+ id: armY
+ rotation: Qt.vector3d(0, 0, 0)
+ color: Qt.rgba(0, 0.6, 0, 1)
+ hoverColor: Qt.lighter(Qt.rgba(0, 0.6, 0, 1))
+ view3D: axisHelperView
+ camRotPos: Qt.vector3d(-90, 0, 0)
+ camRotNeg: Qt.vector3d(90, 0, 0)
+ }
+
+ AxisHelperArm {
+ id: armZ
+ rotation: Qt.vector3d(90, 0, 0)
+ color: Qt.rgba(0, 0, 1, 1)
+ hoverColor: Qt.lighter(Qt.rgba(0, 0, 1, 1))
+ view3D: axisHelperView
+ camRotPos: Qt.vector3d(0, 0, 0)
+ camRotNeg: Qt.vector3d(0, 180, 0)
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ acceptedButtons: Qt.LeftButton
+
+ property var pickObj: null
+
+ function cancelHover()
+ {
+ if (pickObj) {
+ pickObj.hovering = false;
+ pickObj = null;
+ }
+ }
+
+ function pick(mouse)
+ {
+ var result = axisHelperView.pick(mouse.x, mouse.y);
+ if (result.objectHit) {
+ if (result.objectHit !== pickObj) {
+ cancelHover();
+ pickObj = result.objectHit;
+ pickObj.hovering = true;
+ }
+ } else {
+ cancelHover();
+ }
+ }
+
+ onPositionChanged: {
+ pick(mouse);
+ }
+
+ onPressed: {
+ pick(mouse);
+ if (pickObj) {
+ axisHelperView.editCameraCtrl.fitObject(axisHelperView.selectedNode,
+ pickObj.cameraRotation);
+ } else {
+ mouse.accepted = false;
+ }
+ }
+
+ onExited: cancelHover()
+ onCanceled: cancelHover()
+ }
+}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml
new file mode 100644
index 0000000000..23d2f9bbaf
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick3D 1.0
+
+Node {
+ id: armRoot
+ property alias posModel: posModel
+ property alias negModel: negModel
+ property View3D view3D
+ property color hoverColor
+ property color color
+ property vector3d camRotPos
+ property vector3d camRotNeg
+
+ Model {
+ id: posModel
+
+ property bool hovering: false
+ property vector3d cameraRotation: armRoot.camRotPos
+
+ source: "meshes/axishelper.mesh"
+ materials: DefaultMaterial {
+ id: posMat
+ emissiveColor: posModel.hovering ? armRoot.hoverColor : armRoot.color
+ lighting: DefaultMaterial.NoLighting
+ }
+ pickable: true
+ }
+
+ Model {
+ id: negModel
+
+ property bool hovering: false
+ property vector3d cameraRotation: armRoot.camRotNeg
+
+ source: "#Sphere"
+ y: -6
+ scale: Qt.vector3d(0.025, 0.025, 0.025)
+ materials: DefaultMaterial {
+ id: negMat
+ emissiveColor: negModel.hovering ? armRoot.hoverColor : armRoot.color
+ lighting: DefaultMaterial.NoLighting
+ }
+ pickable: true
+ }
+}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
index 90f82bd341..dba7e30f96 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
@@ -30,6 +30,7 @@ Item {
id: cameraCtrl
property Camera camera: null
+ property View3D view3d: null
property vector3d _lookAtPoint
property vector3d _pressPoint
@@ -44,6 +45,15 @@ Item {
property real _defaultCameraLookAtDistance: 0
property Camera _prevCamera: null
+ function fitObject(targetObject, rotation)
+ {
+ camera.rotation = rotation;
+ var newLookAtAndZoom = _generalHelper.fitObjectToCamera(
+ camera, _defaultCameraLookAtDistance, targetObject, view3d);
+ _lookAtPoint = newLookAtAndZoom.toVector3d();
+ _zoomFactor = newLookAtAndZoom.w;
+ }
+
function zoomRelative(distance)
{
_zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance,
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
index 3ce3c5deab..19443113ee 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
@@ -248,8 +248,7 @@ Window {
id: gizmoLabel
targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo
targetView: overlayView
- offsetX: 0
- offsetY: 45
+ offset: Qt.vector3d(0, 45, 0)
visible: targetNode.dragging
Rectangle {
@@ -285,6 +284,7 @@ Window {
id: cameraControl
camera: editView.camera
anchors.fill: parent
+ view3d: editView
}
}
@@ -357,9 +357,18 @@ Window {
}
}
- Column {
- y: 8
+ AxisHelper {
anchors.right: parent.right
+ anchors.top: parent.top
+ width: 100
+ height: width
+ editCameraCtrl: cameraControl
+ selectedNode : viewWindow.selectedNode
+ }
+
+ Column {
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
CheckBox {
id: editLightCheckbox
checked: false
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml
index ebc52a126a..3d4183a9dc 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml
@@ -49,8 +49,6 @@ Node {
id: iconOverlay
targetNode: iconGizmo
targetView: view3D
- offsetX: 0
- offsetY: 0
visible: iconGizmo.visible && !isBehindCamera
parent: view3D
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml
index ce8c85bffb..f4a85226b7 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml
@@ -31,8 +31,7 @@ Item {
property Node targetNode
property View3D targetView
- property real offsetX: 0
- property real offsetY: 0
+ property vector3d offset: Qt.vector3d(0, 0, 0)
property bool isBehindCamera
@@ -56,7 +55,9 @@ Item {
function updateOverlay()
{
var scenePos = targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0);
- var scenePosWithOffset = Qt.vector3d(scenePos.x + offsetX, scenePos.y + offsetY, scenePos.z);
+ var scenePosWithOffset = Qt.vector3d(scenePos.x + offset.x,
+ scenePos.y + offset.y,
+ scenePos.z + offset.z);
var viewPos = targetView ? targetView.mapFrom3DScene(scenePosWithOffset)
: Qt.vector3d(0, 0, 0);
root.x = viewPos.x;
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh
new file mode 100644
index 0000000000..3e9e4958e4
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
index b4872ed48f..e7b091504f 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
@@ -28,7 +28,15 @@
#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
#include <QtQuick3D/private/qquick3dperspectivecamera_p.h>
+#include <QtQuick3D/private/qquick3dobject_p_p.h>
+#include <QtQuick3D/private/qquick3dmodel_p.h>
+#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
+#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
+#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
+#include <QtQuick3DUtils/private/qssgbounds3_p.h>
+#include <QtQuick/qquickwindow.h>
#include <QtCore/qhash.h>
+#include <QtCore/qmath.h>
#include <QtGui/qmatrix4x4.h>
namespace QmlDesigner {
@@ -126,6 +134,57 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
return newZoomFactor;
}
+// Return value contains new lookAt point (xyz) and zoom factor (w)
+QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
+ QQuick3DNode *targetObject, QQuick3DViewport *viewPort)
+{
+ if (!camera)
+ return QVector4D(0.f, 0.f, 0.f, 1.f);
+
+ QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D();
+
+ // Get object bounds
+ qreal maxExtent = 200.;
+ if (auto modelNode = qobject_cast<QQuick3DModel *>(targetObject)) {
+ auto targetPriv = QQuick3DObjectPrivate::get(targetObject);
+ if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
+ QWindow *window = static_cast<QWindow *>(viewPort->window());
+ if (window) {
+ auto context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window));
+ if (!context.isNull()) {
+ auto bufferManager = context->bufferManager();
+ QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager);
+ QVector3D center = bounds.center();
+ const QVector3D e = bounds.extents();
+ const QVector3D s = targetObject->sceneScale();
+ qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z()));
+ maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z()));
+ maxExtent *= maxScale;
+
+ // Adjust lookAt to look directly at the center of the object bounds
+ QMatrix4x4 m = targetObject->sceneTransform();
+ lookAt = m.map(center);
+ }
+ }
+ }
+ }
+
+ // 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();
+ newLookVector *= defaultLookAtDistance;
+
+ camera->setPosition(lookAt + newLookVector);
+
+ // Emprically determined algorithm for nice zoom
+ float newZoomFactor = qBound(.0001f, float(maxExtent / 700.), 10000.f);
+
+ return QVector4D(lookAt,
+ zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false));
+}
+
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
index fbf1658924..f667a97442 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
@@ -28,6 +28,8 @@
#ifdef QUICK3D_MODULE
#include <QtQuick3D/private/qquick3dcamera_p.h>
+#include <QtQuick3D/private/qquick3dnode_p.h>
+#include <QtQuick3D/private/qquick3dviewport_p.h>
#include <QtCore/qobject.h>
#include <QtCore/qtimer.h>
@@ -53,6 +55,8 @@ public:
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
float defaultLookAtDistance, const QVector3D &lookAt,
float zoomFactor, bool relative);
+ Q_INVOKABLE QVector4D fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
+ QQuick3DNode *targetObject, QQuick3DViewport *viewPort);
signals:
void overlayUpdateNeeded();
diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc
index f27f93e0d4..c82164c1ff 100644
--- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc
+++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc
@@ -27,10 +27,13 @@
<file>mockfiles/RotateGizmo.qml</file>
<file>mockfiles/RotateRing.qml</file>
<file>mockfiles/SelectionBox.qml</file>
+ <file>mockfiles/AxisHelper.qml</file>
+ <file>mockfiles/AxisHelperArm.qml</file>
<file>mockfiles/meshes/arrow.mesh</file>
<file>mockfiles/meshes/scalerod.mesh</file>
<file>mockfiles/meshes/ring.mesh</file>
<file>mockfiles/meshes/ringselect.mesh</file>
+ <file>mockfiles/meshes/axishelper.mesh</file>
<file>mockfiles/images/editor_camera.png</file>
<file>mockfiles/images/editor_camera@2x.png</file>
<file>mockfiles/images/light-pick-icon.png</file>