forked from qt-creator/qt-creator
QmlDesigner: Implement better camera navigation in 3D edit view
Edit camera is now controlled as in Qt 3D Studio: ALT + left button orbits camera. ALT + middle button pans camera. ALT + right button zooms camera. Wheel zooms camera. Task-number: QDS-1206 Change-Id: Ia72644073d172b00483ceed8bcc5ffb8dce68741 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -46,7 +46,7 @@ Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: designStudioNativeCameraControlHelper
|
target: _generalHelper
|
||||||
onOverlayUpdateNeeded: updateScale()
|
onOverlayUpdateNeeded: updateScale()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
118
share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
Normal file
118
share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.12
|
||||||
|
import QtQuick3D 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: cameraCtrl
|
||||||
|
|
||||||
|
property Camera camera: null
|
||||||
|
|
||||||
|
property vector3d _lookAtPoint
|
||||||
|
property vector3d _pressPoint
|
||||||
|
property vector3d _prevPoint
|
||||||
|
property vector3d _startRotation
|
||||||
|
property vector3d _startPosition
|
||||||
|
property vector3d _startLookAtPoint
|
||||||
|
property matrix4x4 _startTransform
|
||||||
|
property bool _dragging
|
||||||
|
property int _button
|
||||||
|
property real _zoomFactor: 1
|
||||||
|
property real _defaultCameraLookAtDistance: 0
|
||||||
|
property Camera _prevCamera: null
|
||||||
|
|
||||||
|
function zoomRelative(distance)
|
||||||
|
{
|
||||||
|
_zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance,
|
||||||
|
_lookAtPoint, _zoomFactor, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
cameraCtrl._defaultCameraLookAtDistance = cameraCtrl.camera.position.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCameraChanged: {
|
||||||
|
if (_prevCamera) {
|
||||||
|
// Reset zoom on previous camera to ensure it's properties are good to copy to new cam
|
||||||
|
_generalHelper.zoomCamera(_prevCamera, 0, _defaultCameraLookAtDistance, _lookAtPoint,
|
||||||
|
1, false);
|
||||||
|
|
||||||
|
camera.position = _prevCamera.position;
|
||||||
|
camera.rotation = _prevCamera.rotation;
|
||||||
|
|
||||||
|
// Apply correct zoom to new camera
|
||||||
|
_generalHelper.zoomCamera(camera, 0, _defaultCameraLookAtDistance, _lookAtPoint,
|
||||||
|
_zoomFactor, false);
|
||||||
|
}
|
||||||
|
_prevCamera = camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseHandler
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
|
hoverEnabled: false
|
||||||
|
anchors.fill: parent
|
||||||
|
onPositionChanged: {
|
||||||
|
if (mouse.modifiers === Qt.AltModifier && cameraCtrl._dragging) {
|
||||||
|
var currentPoint = Qt.vector3d(mouse.x, mouse.y, 0);
|
||||||
|
if (cameraCtrl._button == Qt.LeftButton) {
|
||||||
|
_generalHelper.orbitCamera(cameraCtrl.camera, cameraCtrl._startRotation,
|
||||||
|
cameraCtrl._lookAtPoint, cameraCtrl._pressPoint,
|
||||||
|
currentPoint);
|
||||||
|
} else if (cameraCtrl._button == Qt.MiddleButton) {
|
||||||
|
cameraCtrl._lookAtPoint = _generalHelper.panCamera(
|
||||||
|
cameraCtrl.camera, cameraCtrl._startTransform,
|
||||||
|
cameraCtrl._startPosition, cameraCtrl._startLookAtPoint,
|
||||||
|
cameraCtrl._pressPoint, currentPoint, _zoomFactor);
|
||||||
|
} else if (cameraCtrl._button == Qt.RightButton) {
|
||||||
|
cameraCtrl.zoomRelative(currentPoint.y - cameraCtrl._prevPoint.y)
|
||||||
|
cameraCtrl._prevPoint = currentPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onPressed: {
|
||||||
|
if (mouse.modifiers === Qt.AltModifier) {
|
||||||
|
cameraCtrl._dragging = true;
|
||||||
|
cameraCtrl._startRotation = cameraCtrl.camera.rotation;
|
||||||
|
cameraCtrl._startPosition = cameraCtrl.camera.position;
|
||||||
|
cameraCtrl._startLookAtPoint = _lookAtPoint;
|
||||||
|
cameraCtrl._pressPoint = Qt.vector3d(mouse.x, mouse.y, 0);
|
||||||
|
cameraCtrl._prevPoint = cameraCtrl._pressPoint;
|
||||||
|
cameraCtrl._button = mouse.button;
|
||||||
|
cameraCtrl._startTransform = cameraCtrl.camera.sceneTransform;
|
||||||
|
} else {
|
||||||
|
mouse.accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onReleased: cameraCtrl._dragging = false;
|
||||||
|
onCanceled: cameraCtrl._dragging = false;
|
||||||
|
onWheel: {
|
||||||
|
// Emprically determined divisor for nice zoom
|
||||||
|
cameraCtrl.zoomRelative(wheel.angleDelta.y / -40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -26,7 +26,6 @@
|
|||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
import QtQuick.Window 2.0
|
import QtQuick.Window 2.0
|
||||||
import QtQuick3D 1.0
|
import QtQuick3D 1.0
|
||||||
import QtQuick3D.Helpers 1.0
|
|
||||||
import QtQuick.Controls 2.0
|
import QtQuick.Controls 2.0
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ Window {
|
|||||||
{
|
{
|
||||||
var component = Qt.createComponent("CameraGizmo.qml");
|
var component = Qt.createComponent("CameraGizmo.qml");
|
||||||
if (component.status === Component.Ready) {
|
if (component.status === Component.Ready) {
|
||||||
var geometryName = designStudioNativeCameraControlHelper.generateUniqueName("CameraGeometry");
|
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
|
||||||
var gizmo = component.createObject(
|
var gizmo = component.createObject(
|
||||||
overlayScene,
|
overlayScene,
|
||||||
{"view3D": overlayView, "targetNode": obj, "geometryName": geometryName,
|
{"view3D": overlayView, "targetNode": obj, "geometryName": geometryName,
|
||||||
@@ -92,10 +91,10 @@ Window {
|
|||||||
|
|
||||||
// Work-around the fact that the projection matrix for the camera is not calculated until
|
// Work-around the fact that the projection matrix for the camera is not calculated until
|
||||||
// the first frame is rendered, so any initial calls to mapFrom3DScene() will fail.
|
// the first frame is rendered, so any initial calls to mapFrom3DScene() will fail.
|
||||||
Component.onCompleted: designStudioNativeCameraControlHelper.requestOverlayUpdate();
|
Component.onCompleted: _generalHelper.requestOverlayUpdate();
|
||||||
|
|
||||||
onWidthChanged: designStudioNativeCameraControlHelper.requestOverlayUpdate();
|
onWidthChanged: _generalHelper.requestOverlayUpdate();
|
||||||
onHeightChanged: designStudioNativeCameraControlHelper.requestOverlayUpdate();
|
onHeightChanged: _generalHelper.requestOverlayUpdate();
|
||||||
|
|
||||||
Node {
|
Node {
|
||||||
id: overlayScene
|
id: overlayScene
|
||||||
@@ -114,6 +113,7 @@ Window {
|
|||||||
clipNear: editOrthoCamera.clipNear
|
clipNear: editOrthoCamera.clipNear
|
||||||
position: editOrthoCamera.position
|
position: editOrthoCamera.position
|
||||||
rotation: editOrthoCamera.rotation
|
rotation: editOrthoCamera.rotation
|
||||||
|
scale: editOrthoCamera.scale
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveGizmo {
|
MoveGizmo {
|
||||||
@@ -209,11 +209,14 @@ Window {
|
|||||||
linearFade: 0
|
linearFade: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initial camera position and rotation should be such that they look at origin.
|
||||||
|
// Otherwise EditCameraController._lookAtPoint needs to be initialized to correct
|
||||||
|
// point.
|
||||||
PerspectiveCamera {
|
PerspectiveCamera {
|
||||||
id: editPerspectiveCamera
|
id: editPerspectiveCamera
|
||||||
z: -600
|
z: -600
|
||||||
y: 200
|
y: 600
|
||||||
rotation.x: 30
|
rotation.x: 45
|
||||||
clipFar: 100000
|
clipFar: 100000
|
||||||
clipNear: 1
|
clipNear: 1
|
||||||
}
|
}
|
||||||
@@ -221,8 +224,8 @@ Window {
|
|||||||
OrthographicCamera {
|
OrthographicCamera {
|
||||||
id: editOrthoCamera
|
id: editOrthoCamera
|
||||||
z: -600
|
z: -600
|
||||||
y: 200
|
y: 600
|
||||||
rotation.x: 30
|
rotation.x: 45
|
||||||
clipFar: 100000
|
clipFar: 100000
|
||||||
clipNear: 1
|
clipNear: 1
|
||||||
}
|
}
|
||||||
@@ -273,19 +276,10 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WasdController {
|
EditCameraController {
|
||||||
id: cameraControl
|
id: cameraControl
|
||||||
controlledObject: editView.camera
|
camera: editView.camera
|
||||||
acceptedButtons: Qt.RightButton
|
anchors.fill: parent
|
||||||
|
|
||||||
onInputsNeedProcessingChanged: designStudioNativeCameraControlHelper.enabled
|
|
||||||
= cameraControl.inputsNeedProcessing
|
|
||||||
|
|
||||||
// Use separate native timer as QML timers don't work inside Qt Design Studio
|
|
||||||
Connections {
|
|
||||||
target: designStudioNativeCameraControlHelper
|
|
||||||
onUpdateInputs: cameraControl.processInputs()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,39 +359,25 @@ Window {
|
|||||||
id: editLightCheckbox
|
id: editLightCheckbox
|
||||||
checked: false
|
checked: false
|
||||||
text: qsTr("Use Edit View Light")
|
text: qsTr("Use Edit View Light")
|
||||||
onCheckedChanged: cameraControl.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: usePerspectiveCheckbox
|
id: usePerspectiveCheckbox
|
||||||
checked: true
|
checked: true
|
||||||
text: qsTr("Use Perspective Projection")
|
text: qsTr("Use Perspective Projection")
|
||||||
onCheckedChanged: {
|
onCheckedChanged: _generalHelper.requestOverlayUpdate()
|
||||||
// Since WasdController always acts on active camera, we need to update pos/rot
|
|
||||||
// to the other camera when we change
|
|
||||||
if (checked) {
|
|
||||||
editPerspectiveCamera.position = editOrthoCamera.position;
|
|
||||||
editPerspectiveCamera.rotation = editOrthoCamera.rotation;
|
|
||||||
} else {
|
|
||||||
editOrthoCamera.position = editPerspectiveCamera.position;
|
|
||||||
editOrthoCamera.rotation = editPerspectiveCamera.rotation;
|
|
||||||
}
|
|
||||||
designStudioNativeCameraControlHelper.requestOverlayUpdate();
|
|
||||||
cameraControl.forceActiveFocus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: globalControl
|
id: globalControl
|
||||||
checked: true
|
checked: true
|
||||||
text: qsTr("Use Global Orientation")
|
text: qsTr("Use Global Orientation")
|
||||||
onCheckedChanged: cameraControl.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: helpText
|
id: helpText
|
||||||
text: qsTr("Camera: W,A,S,D,R,F,right mouse drag")
|
text: qsTr("Camera controls: ALT + mouse press and drag. Left: Rotate, Middle: Pan, Right/Wheel: Zoom.")
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -49,7 +49,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: designStudioNativeCameraControlHelper
|
target: _generalHelper
|
||||||
onOverlayUpdateNeeded: updateOverlay()
|
onOverlayUpdateNeeded: updateOverlay()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,78 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
#include "cameracontrolhelper.h"
|
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
CameraControlHelper::CameraControlHelper()
|
|
||||||
: QObject()
|
|
||||||
{
|
|
||||||
m_inputUpdateTimer.setInterval(16);
|
|
||||||
QObject::connect(&m_inputUpdateTimer, &QTimer::timeout,
|
|
||||||
this, &CameraControlHelper::handleUpdateTimer);
|
|
||||||
|
|
||||||
m_overlayUpdateTimer.setInterval(16);
|
|
||||||
m_overlayUpdateTimer.setSingleShot(true);
|
|
||||||
QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout,
|
|
||||||
this, &CameraControlHelper::overlayUpdateNeeded);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CameraControlHelper::enabled()
|
|
||||||
{
|
|
||||||
return m_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CameraControlHelper::handleUpdateTimer()
|
|
||||||
{
|
|
||||||
emit updateInputs();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CameraControlHelper::setEnabled(bool enabled)
|
|
||||||
{
|
|
||||||
if (enabled)
|
|
||||||
m_inputUpdateTimer.start();
|
|
||||||
else
|
|
||||||
m_inputUpdateTimer.stop();
|
|
||||||
m_enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CameraControlHelper::requestOverlayUpdate()
|
|
||||||
{
|
|
||||||
if (!m_overlayUpdateTimer.isActive())
|
|
||||||
m_overlayUpdateTimer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CameraControlHelper::generateUniqueName(const QString &nameRoot)
|
|
||||||
{
|
|
||||||
static QHash<QString, int> counters;
|
|
||||||
int count = counters[nameRoot]++;
|
|
||||||
return QStringLiteral("%1_%2").arg(nameRoot).arg(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +1,9 @@
|
|||||||
HEADERS += $$PWD/cameracontrolhelper.h \
|
HEADERS += $$PWD/generalhelper.h \
|
||||||
$$PWD/mousearea3d.h \
|
$$PWD/mousearea3d.h \
|
||||||
$$PWD/camerageometry.h \
|
$$PWD/camerageometry.h \
|
||||||
$$PWD/gridgeometry.h
|
$$PWD/gridgeometry.h
|
||||||
|
|
||||||
SOURCES += $$PWD/cameracontrolhelper.cpp \
|
SOURCES += $$PWD/generalhelper.cpp \
|
||||||
$$PWD/mousearea3d.cpp \
|
$$PWD/mousearea3d.cpp \
|
||||||
$$PWD/camerageometry.cpp \
|
$$PWD/camerageometry.cpp \
|
||||||
$$PWD/gridgeometry.cpp
|
$$PWD/gridgeometry.cpp
|
||||||
|
@@ -0,0 +1,132 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#include "generalhelper.h"
|
||||||
|
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
|
||||||
|
#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dperspectivecamera_p.h>
|
||||||
|
#include <QtCore/qhash.h>
|
||||||
|
#include <QtGui/qmatrix4x4.h>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
GeneralHelper::GeneralHelper()
|
||||||
|
: QObject()
|
||||||
|
{
|
||||||
|
m_overlayUpdateTimer.setInterval(16);
|
||||||
|
m_overlayUpdateTimer.setSingleShot(true);
|
||||||
|
QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout,
|
||||||
|
this, &GeneralHelper::overlayUpdateNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneralHelper::requestOverlayUpdate()
|
||||||
|
{
|
||||||
|
if (!m_overlayUpdateTimer.isActive())
|
||||||
|
m_overlayUpdateTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GeneralHelper::generateUniqueName(const QString &nameRoot)
|
||||||
|
{
|
||||||
|
static QHash<QString, int> counters;
|
||||||
|
int count = counters[nameRoot]++;
|
||||||
|
return QStringLiteral("%1_%2").arg(nameRoot).arg(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneralHelper::orbitCamera(QQuick3DCamera *camera, const QVector3D &startRotation,
|
||||||
|
const QVector3D &lookAtPoint, const QVector3D &pressPos,
|
||||||
|
const QVector3D ¤tPos)
|
||||||
|
{
|
||||||
|
QVector3D dragVector = currentPos - pressPos;
|
||||||
|
|
||||||
|
if (dragVector.length() < 0.001f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
camera->setRotation(startRotation);
|
||||||
|
QVector3D newRotation(dragVector.y(), dragVector.x(), 0.f);
|
||||||
|
newRotation *= 0.5f; // Emprically determined multiplier for nice drag
|
||||||
|
newRotation += startRotation;
|
||||||
|
|
||||||
|
camera->setRotation(newRotation);
|
||||||
|
|
||||||
|
const QVector3D oldLookVector = camera->position() - lookAtPoint;
|
||||||
|
QMatrix4x4 m = camera->sceneTransform();
|
||||||
|
const float *dataPtr(m.data());
|
||||||
|
QVector3D newLookVector(-dataPtr[8], -dataPtr[9], -dataPtr[10]);
|
||||||
|
newLookVector.normalize();
|
||||||
|
newLookVector *= oldLookVector.length();
|
||||||
|
|
||||||
|
camera->setPosition(lookAtPoint + newLookVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pans camera and returns the new look-at point
|
||||||
|
QVector3D GeneralHelper::panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform,
|
||||||
|
const QVector3D &startPosition, const QVector3D &startLookAt,
|
||||||
|
const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||||
|
float zoomFactor)
|
||||||
|
{
|
||||||
|
QVector3D dragVector = currentPos - pressPos;
|
||||||
|
|
||||||
|
if (dragVector.length() < 0.001f)
|
||||||
|
return startLookAt;
|
||||||
|
|
||||||
|
const float *dataPtr(startTransform.data());
|
||||||
|
const QVector3D xAxis = QVector3D(dataPtr[0], dataPtr[1], dataPtr[2]).normalized();
|
||||||
|
const QVector3D yAxis = QVector3D(dataPtr[4], dataPtr[5], dataPtr[6]).normalized();
|
||||||
|
const QVector3D xDelta = -1.f * xAxis * dragVector.x();
|
||||||
|
const QVector3D yDelta = yAxis * dragVector.y();
|
||||||
|
const QVector3D delta = (xDelta + yDelta) * zoomFactor;
|
||||||
|
|
||||||
|
camera->setPosition(startPosition + delta);
|
||||||
|
return startLookAt + delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float defaultLookAtDistance,
|
||||||
|
const QVector3D &lookAt, float zoomFactor, bool relative)
|
||||||
|
{
|
||||||
|
// Emprically determined divisor for nice zoom
|
||||||
|
float multiplier = 1.f + (distance / 40.f);
|
||||||
|
float newZoomFactor = relative ? qBound(.0001f, zoomFactor * multiplier, 10000.f)
|
||||||
|
: zoomFactor;
|
||||||
|
|
||||||
|
if (qobject_cast<QQuick3DOrthographicCamera *>(camera)) {
|
||||||
|
// Ortho camera we can simply scale
|
||||||
|
camera->setScale(QVector3D(newZoomFactor, newZoomFactor, newZoomFactor));
|
||||||
|
} else if (qobject_cast<QQuick3DPerspectiveCamera *>(camera)) {
|
||||||
|
// Perspective camera is zoomed by moving camera forward or backward while keeping the
|
||||||
|
// look-at point the same
|
||||||
|
const QVector3D lookAtVec = (camera->position() - lookAt).normalized();
|
||||||
|
const float newDistance = defaultLookAtDistance * newZoomFactor;
|
||||||
|
camera->setPosition(lookAt + (lookAtVec * newDistance));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newZoomFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // QUICK3D_MODULE
|
@@ -25,38 +25,43 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#ifdef QUICK3D_MODULE
|
||||||
#include <QtCore/QTimer>
|
|
||||||
|
#include <QtQuick3D/private/qquick3dcamera_p.h>
|
||||||
|
#include <QtCore/qobject.h>
|
||||||
|
#include <QtCore/qtimer.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class CameraControlHelper : public QObject
|
class GeneralHelper : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CameraControlHelper();
|
GeneralHelper();
|
||||||
|
|
||||||
bool enabled();
|
|
||||||
void setEnabled(bool enabled);
|
|
||||||
|
|
||||||
Q_INVOKABLE void requestOverlayUpdate();
|
Q_INVOKABLE void requestOverlayUpdate();
|
||||||
Q_INVOKABLE QString generateUniqueName(const QString &nameRoot);
|
Q_INVOKABLE QString generateUniqueName(const QString &nameRoot);
|
||||||
|
|
||||||
public slots:
|
Q_INVOKABLE void orbitCamera(QQuick3DCamera *camera, const QVector3D &startRotation,
|
||||||
void handleUpdateTimer();
|
const QVector3D &lookAtPoint, const QVector3D &pressPos,
|
||||||
|
const QVector3D ¤tPos);
|
||||||
|
Q_INVOKABLE QVector3D panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform,
|
||||||
|
const QVector3D &startPosition, const QVector3D &startLookAt,
|
||||||
|
const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||||
|
float zoomFactor);
|
||||||
|
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
||||||
|
float defaultLookAtDistance, const QVector3D &lookAt,
|
||||||
|
float zoomFactor, bool relative);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateInputs();
|
|
||||||
void enabledChanged(bool enabled);
|
|
||||||
void overlayUpdateNeeded();
|
void overlayUpdateNeeded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_enabled = false;
|
|
||||||
QTimer m_inputUpdateTimer;
|
|
||||||
QTimer m_overlayUpdateTimer;
|
QTimer m_overlayUpdateTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // QUICK3D_MODULE
|
@@ -37,7 +37,6 @@ namespace QmlDesigner {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
|
MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
|
||||||
static const qreal s_mouseDragMultiplier = .02;
|
|
||||||
|
|
||||||
MouseArea3D::MouseArea3D(QQuick3DNode *parent)
|
MouseArea3D::MouseArea3D(QQuick3DNode *parent)
|
||||||
: QQuick3DNode(parent)
|
: QQuick3DNode(parent)
|
||||||
@@ -340,7 +339,7 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
|||||||
dragDir = (screenDragDir - nodePos).normalized();
|
dragDir = (screenDragDir - nodePos).normalized();
|
||||||
const QVector3D pressToCurrent = (currentPos - pressPos);
|
const QVector3D pressToCurrent = (currentPos - pressPos);
|
||||||
float magnitude = QVector3D::dotProduct(pressToCurrent, dragDir);
|
float magnitude = QVector3D::dotProduct(pressToCurrent, dragDir);
|
||||||
qreal angle = -s_mouseDragMultiplier * qreal(magnitude);
|
qreal angle = -mouseDragMultiplier() * qreal(magnitude);
|
||||||
return angle;
|
return angle;
|
||||||
} else {
|
} else {
|
||||||
const QVector3D nodeToPress = (pressPos - nodePos).normalized();
|
const QVector3D nodeToPress = (pressPos - nodePos).normalized();
|
||||||
@@ -397,7 +396,7 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo
|
|||||||
|
|
||||||
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
|
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
|
||||||
|
|
||||||
qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * s_mouseDragMultiplier);
|
qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * mouseDragMultiplier());
|
||||||
|
|
||||||
finalAxis.normalize();
|
finalAxis.normalize();
|
||||||
|
|
||||||
|
@@ -51,7 +51,7 @@ class MouseArea3D : public QQuick3DNode
|
|||||||
Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged)
|
Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged)
|
||||||
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
|
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
|
||||||
Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
|
Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
|
||||||
Q_PROPERTY(int active READ active WRITE setActive NOTIFY activeChanged)
|
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
|
||||||
Q_PROPERTY(QPointF circlePickArea READ circlePickArea WRITE setCirclePickArea NOTIFY circlePickAreaChanged)
|
Q_PROPERTY(QPointF circlePickArea READ circlePickArea WRITE setCirclePickArea NOTIFY circlePickAreaChanged)
|
||||||
Q_PROPERTY(qreal minAngle READ minAngle WRITE setMinAngle NOTIFY minAngleChanged)
|
Q_PROPERTY(qreal minAngle READ minAngle WRITE setMinAngle NOTIFY minAngleChanged)
|
||||||
Q_PROPERTY(QQuick3DNode *pickNode READ pickNode WRITE setPickNode NOTIFY pickNodeChanged)
|
Q_PROPERTY(QQuick3DNode *pickNode READ pickNode WRITE setPickNode NOTIFY pickNodeChanged)
|
||||||
@@ -77,6 +77,8 @@ public:
|
|||||||
qreal minAngle() const;
|
qreal minAngle() const;
|
||||||
QQuick3DNode *pickNode() const;
|
QQuick3DNode *pickNode() const;
|
||||||
|
|
||||||
|
static qreal mouseDragMultiplier() { return .02; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setView3D(QQuick3DViewport *view3D);
|
void setView3D(QQuick3DViewport *view3D);
|
||||||
void setGrabsMouse(bool grabsMouse);
|
void setGrabsMouse(bool grabsMouse);
|
||||||
@@ -157,7 +159,7 @@ private:
|
|||||||
QVector3D getMousePosInPlane(const QPointF &mousePosInView) const;
|
QVector3D getMousePosInPlane(const QPointF &mousePosInView) const;
|
||||||
|
|
||||||
static MouseArea3D *s_mouseGrab;
|
static MouseArea3D *s_mouseGrab;
|
||||||
bool m_grabsMouse;
|
bool m_grabsMouse = false;
|
||||||
QVector3D m_mousePosInPlane;
|
QVector3D m_mousePosInPlane;
|
||||||
QPointF m_circlePickArea;
|
QPointF m_circlePickArea;
|
||||||
qreal m_minAngle = 0.;
|
qreal m_minAngle = 0.;
|
||||||
|
@@ -62,7 +62,7 @@
|
|||||||
#include <drop3dlibraryitemcommand.h>
|
#include <drop3dlibraryitemcommand.h>
|
||||||
|
|
||||||
#include "dummycontextobject.h"
|
#include "dummycontextobject.h"
|
||||||
#include "../editor3d/cameracontrolhelper.h"
|
#include "../editor3d/generalhelper.h"
|
||||||
#include "../editor3d/mousearea3d.h"
|
#include "../editor3d/mousearea3d.h"
|
||||||
#include "../editor3d/camerageometry.h"
|
#include "../editor3d/camerageometry.h"
|
||||||
#include "../editor3d/gridgeometry.h"
|
#include "../editor3d/gridgeometry.h"
|
||||||
@@ -104,10 +104,9 @@ bool Qt5InformationNodeInstanceServer::eventFilter(QObject *, QEvent *event)
|
|||||||
|
|
||||||
QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||||
{
|
{
|
||||||
auto helper = new QmlDesigner::Internal::CameraControlHelper();
|
|
||||||
engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper);
|
|
||||||
|
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
|
auto helper = new QmlDesigner::Internal::GeneralHelper();
|
||||||
|
engine->rootContext()->setContextProperty("_generalHelper", helper);
|
||||||
qmlRegisterType<QmlDesigner::Internal::MouseArea3D>("MouseArea3D", 1, 0, "MouseArea3D");
|
qmlRegisterType<QmlDesigner::Internal::MouseArea3D>("MouseArea3D", 1, 0, "MouseArea3D");
|
||||||
qmlRegisterType<QmlDesigner::Internal::CameraGeometry>("CameraGeometry", 1, 0, "CameraGeometry");
|
qmlRegisterType<QmlDesigner::Internal::CameraGeometry>("CameraGeometry", 1, 0, "CameraGeometry");
|
||||||
qmlRegisterType<QmlDesigner::Internal::GridGeometry>("GridGeometry", 1, 0, "GridGeometry");
|
qmlRegisterType<QmlDesigner::Internal::GridGeometry>("GridGeometry", 1, 0, "GridGeometry");
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
<file>mockfiles/GenericBackend.qml</file>
|
<file>mockfiles/GenericBackend.qml</file>
|
||||||
<file>mockfiles/Dialog.qml</file>
|
<file>mockfiles/Dialog.qml</file>
|
||||||
<file>mockfiles/EditView3D.qml</file>
|
<file>mockfiles/EditView3D.qml</file>
|
||||||
|
<file>mockfiles/EditCameraController.qml</file>
|
||||||
<file>mockfiles/Arrow.qml</file>
|
<file>mockfiles/Arrow.qml</file>
|
||||||
<file>mockfiles/AutoScaleHelper.qml</file>
|
<file>mockfiles/AutoScaleHelper.qml</file>
|
||||||
<file>mockfiles/MoveGizmo.qml</file>
|
<file>mockfiles/MoveGizmo.qml</file>
|
||||||
|
@@ -108,7 +108,7 @@ extend_qtc_executable(qml2puppet
|
|||||||
extend_qtc_executable(qml2puppet
|
extend_qtc_executable(qml2puppet
|
||||||
SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d"
|
SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d"
|
||||||
SOURCES
|
SOURCES
|
||||||
cameracontrolhelper.cpp cameracontrolhelper.h
|
generalhelper.cpp generalhelper.h
|
||||||
mousearea3d.cpp mousearea3d.h
|
mousearea3d.cpp mousearea3d.h
|
||||||
camerageometry.cpp camerageometry.h
|
camerageometry.cpp camerageometry.h
|
||||||
gridgeometry.cpp gridgeometry.h
|
gridgeometry.cpp gridgeometry.h
|
||||||
|
@@ -197,8 +197,8 @@ QtcTool {
|
|||||||
"instances/qt5testnodeinstanceserver.h",
|
"instances/qt5testnodeinstanceserver.h",
|
||||||
"instances/servernodeinstance.cpp",
|
"instances/servernodeinstance.cpp",
|
||||||
"instances/servernodeinstance.h",
|
"instances/servernodeinstance.h",
|
||||||
"editor3d/cameracontrolhelper.cpp",
|
"editor3d/generalhelper.cpp",
|
||||||
"editor3d/cameracontrolhelper.h",
|
"editor3d/generalhelper.h",
|
||||||
"editor3d/mousearea3d.cpp",
|
"editor3d/mousearea3d.cpp",
|
||||||
"editor3d/mousearea3d.h",
|
"editor3d/mousearea3d.h",
|
||||||
"editor3d/camerageometry.cpp",
|
"editor3d/camerageometry.cpp",
|
||||||
|
Reference in New Issue
Block a user