forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -81,6 +81,7 @@ Node {
|
|||||||
|
|
||||||
MouseArea3D {
|
MouseArea3D {
|
||||||
id: helper
|
id: helper
|
||||||
|
active: false
|
||||||
view3D: overlayNode.view3D
|
view3D: overlayNode.view3D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
133
share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
Normal file
133
share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
Normal file
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
70
share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml
Normal file
70
share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
@@ -30,6 +30,7 @@ Item {
|
|||||||
id: cameraCtrl
|
id: cameraCtrl
|
||||||
|
|
||||||
property Camera camera: null
|
property Camera camera: null
|
||||||
|
property View3D view3d: null
|
||||||
|
|
||||||
property vector3d _lookAtPoint
|
property vector3d _lookAtPoint
|
||||||
property vector3d _pressPoint
|
property vector3d _pressPoint
|
||||||
@@ -44,6 +45,15 @@ Item {
|
|||||||
property real _defaultCameraLookAtDistance: 0
|
property real _defaultCameraLookAtDistance: 0
|
||||||
property Camera _prevCamera: null
|
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)
|
function zoomRelative(distance)
|
||||||
{
|
{
|
||||||
_zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance,
|
_zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance,
|
||||||
|
@@ -248,8 +248,7 @@ Window {
|
|||||||
id: gizmoLabel
|
id: gizmoLabel
|
||||||
targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo
|
targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo
|
||||||
targetView: overlayView
|
targetView: overlayView
|
||||||
offsetX: 0
|
offset: Qt.vector3d(0, 45, 0)
|
||||||
offsetY: 45
|
|
||||||
visible: targetNode.dragging
|
visible: targetNode.dragging
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -285,6 +284,7 @@ Window {
|
|||||||
id: cameraControl
|
id: cameraControl
|
||||||
camera: editView.camera
|
camera: editView.camera
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
view3d: editView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,9 +357,18 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
AxisHelper {
|
||||||
y: 8
|
|
||||||
anchors.right: parent.right
|
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 {
|
CheckBox {
|
||||||
id: editLightCheckbox
|
id: editLightCheckbox
|
||||||
checked: false
|
checked: false
|
||||||
|
@@ -49,8 +49,6 @@ Node {
|
|||||||
id: iconOverlay
|
id: iconOverlay
|
||||||
targetNode: iconGizmo
|
targetNode: iconGizmo
|
||||||
targetView: view3D
|
targetView: view3D
|
||||||
offsetX: 0
|
|
||||||
offsetY: 0
|
|
||||||
visible: iconGizmo.visible && !isBehindCamera
|
visible: iconGizmo.visible && !isBehindCamera
|
||||||
parent: view3D
|
parent: view3D
|
||||||
|
|
||||||
|
@@ -31,8 +31,7 @@ Item {
|
|||||||
property Node targetNode
|
property Node targetNode
|
||||||
property View3D targetView
|
property View3D targetView
|
||||||
|
|
||||||
property real offsetX: 0
|
property vector3d offset: Qt.vector3d(0, 0, 0)
|
||||||
property real offsetY: 0
|
|
||||||
|
|
||||||
property bool isBehindCamera
|
property bool isBehindCamera
|
||||||
|
|
||||||
@@ -56,7 +55,9 @@ Item {
|
|||||||
function updateOverlay()
|
function updateOverlay()
|
||||||
{
|
{
|
||||||
var scenePos = targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0);
|
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)
|
var viewPos = targetView ? targetView.mapFrom3DScene(scenePosWithOffset)
|
||||||
: Qt.vector3d(0, 0, 0);
|
: Qt.vector3d(0, 0, 0);
|
||||||
root.x = viewPos.x;
|
root.x = viewPos.x;
|
||||||
|
BIN
share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh
Normal file
BIN
share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh
Normal file
Binary file not shown.
@@ -28,7 +28,15 @@
|
|||||||
|
|
||||||
#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
|
#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
|
||||||
#include <QtQuick3D/private/qquick3dperspectivecamera_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/qhash.h>
|
||||||
|
#include <QtCore/qmath.h>
|
||||||
#include <QtGui/qmatrix4x4.h>
|
#include <QtGui/qmatrix4x4.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -126,6 +134,57 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
|
|||||||
return newZoomFactor;
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,6 +28,8 @@
|
|||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
|
|
||||||
#include <QtQuick3D/private/qquick3dcamera_p.h>
|
#include <QtQuick3D/private/qquick3dcamera_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dnode_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dviewport_p.h>
|
||||||
#include <QtCore/qobject.h>
|
#include <QtCore/qobject.h>
|
||||||
#include <QtCore/qtimer.h>
|
#include <QtCore/qtimer.h>
|
||||||
|
|
||||||
@@ -53,6 +55,8 @@ public:
|
|||||||
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
||||||
float defaultLookAtDistance, const QVector3D &lookAt,
|
float defaultLookAtDistance, const QVector3D &lookAt,
|
||||||
float zoomFactor, bool relative);
|
float zoomFactor, bool relative);
|
||||||
|
Q_INVOKABLE QVector4D fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||||
|
QQuick3DNode *targetObject, QQuick3DViewport *viewPort);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void overlayUpdateNeeded();
|
void overlayUpdateNeeded();
|
||||||
|
@@ -27,10 +27,13 @@
|
|||||||
<file>mockfiles/RotateGizmo.qml</file>
|
<file>mockfiles/RotateGizmo.qml</file>
|
||||||
<file>mockfiles/RotateRing.qml</file>
|
<file>mockfiles/RotateRing.qml</file>
|
||||||
<file>mockfiles/SelectionBox.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/arrow.mesh</file>
|
||||||
<file>mockfiles/meshes/scalerod.mesh</file>
|
<file>mockfiles/meshes/scalerod.mesh</file>
|
||||||
<file>mockfiles/meshes/ring.mesh</file>
|
<file>mockfiles/meshes/ring.mesh</file>
|
||||||
<file>mockfiles/meshes/ringselect.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.png</file>
|
||||||
<file>mockfiles/images/editor_camera@2x.png</file>
|
<file>mockfiles/images/editor_camera@2x.png</file>
|
||||||
<file>mockfiles/images/light-pick-icon.png</file>
|
<file>mockfiles/images/light-pick-icon.png</file>
|
||||||
|
Reference in New Issue
Block a user