QmlDesigner: Fix 3D edit gizmos orientation and rotation order

When selected node has non-default rotation order or orientation,
gizmos need to account for that.

Change-Id: Ie3817fd057b43f708ac1feea3e98e1e44f56d66a
Fixes: QDS-1290
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miikka Heikkinen
2019-12-03 14:16:42 +02:00
parent 056080b599
commit 4ce7f39e4e
10 changed files with 93 additions and 32 deletions

View File

@@ -33,15 +33,18 @@ Node {
property View3D view3D property View3D view3D
property Node target: parent property Node target: parent
property bool autoScale: true property bool autoScale: true
property Camera camera: view3D.camera
// Read-only // Read-only
property real relativeScale: 1 property real relativeScale: 1
onSceneTransformChanged: updateScale() onSceneTransformChanged: updateScale()
onAutoScaleChanged: updateScale() onAutoScaleChanged: updateScale()
// Trigger delayed update on camera change to ensure camera values are correct
onCameraChanged: _generalHelper.requestOverlayUpdate();
Connections { Connections {
target: view3D.camera target: camera
onSceneTransformChanged: updateScale() onSceneTransformChanged: updateScale()
} }
@@ -66,16 +69,22 @@ Node {
// "anchor" distance. Map the two positions back to the target node, and measure the // "anchor" distance. Map the two positions back to the target node, and measure the
// distance between them now, in the 3D scene. The difference of the two distances, // distance between them now, in the 3D scene. The difference of the two distances,
// view and scene, will tell us what the distance independent scale should be. // view and scene, will tell us what the distance independent scale should be.
var posInView1 = view3D.mapFrom3DScene(scenePosition);
// Need to recreate vector as we need to adjust it and we can't do that on reference of
// scenePosition, which is read-only property
var scenePos = Qt.vector3d(scenePosition.x, scenePosition.y, scenePosition.z);
if (orientation === Node.RightHanded)
scenePos.z = -scenePos.z;
var posInView1 = view3D.mapFrom3DScene(scenePos);
var posInView2 = Qt.vector3d(posInView1.x + 100, posInView1.y, posInView1.z); var posInView2 = Qt.vector3d(posInView1.x + 100, posInView1.y, posInView1.z);
var rayPos1 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 0)); var rayPos1 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 0));
var rayPos2 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 10)); var rayPos2 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 10));
var planeNormal = view3D.camera.forward; var planeNormal = camera.forward;
var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, scenePosition, var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, scenePos, planeNormal);
planeNormal); relativeScale = scenePos.minus(rayHitPos).length() / 100;
relativeScale = scenePosition.minus(rayHitPos).length() / 100;
} }
} }

View File

@@ -29,7 +29,6 @@ import MouseArea3D 1.0
Model { Model {
id: rootModel id: rootModel
rotationOrder: Node.XYZr
property View3D view3D property View3D view3D
property alias color: material.emissiveColor property alias color: material.emissiveColor
@@ -59,6 +58,8 @@ Model {
var maskedPosition = Qt.vector3d(scenePos.x, 0, 0); var maskedPosition = Qt.vector3d(scenePos.x, 0, 0);
_pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition);
if (targetNode.orientation === Node.RightHanded)
_pointerPosPressed.z = -_pointerPosPressed.z;
var sp = targetNode.scenePosition; var sp = targetNode.scenePosition;
_targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
pressed(mouseArea); pressed(mouseArea);
@@ -68,9 +69,9 @@ Model {
{ {
var maskedPosition = Qt.vector3d(scenePos.x, 0, 0); var maskedPosition = Qt.vector3d(scenePos.x, 0, 0);
var scenePointerPos = mouseArea.mapPositionToScene(maskedPosition); var scenePointerPos = mouseArea.mapPositionToScene(maskedPosition);
return Qt.vector3d(scenePointerPos.x - _pointerPosPressed.x, if (targetNode.orientation === Node.RightHanded)
scenePointerPos.y - _pointerPosPressed.y, scenePointerPos.z = -scenePointerPos.z;
scenePointerPos.z - _pointerPosPressed.z); return scenePointerPos.minus(_pointerPosPressed);
} }
function handleDragged(mouseArea, scenePos) function handleDragged(mouseArea, scenePos)

View File

@@ -188,8 +188,6 @@ Window {
scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
highlightOnHover: true highlightOnHover: true
targetNode: viewWindow.selectedNode targetNode: viewWindow.selectedNode
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
: Qt.vector3d(0, 0, 0)
globalOrientation: btnLocalGlobal.toggled globalOrientation: btnLocalGlobal.toggled
visible: selectedNode && btnMove.selected visible: selectedNode && btnMove.selected
view3D: overlayView view3D: overlayView
@@ -203,8 +201,6 @@ Window {
scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
highlightOnHover: true highlightOnHover: true
targetNode: viewWindow.selectedNode targetNode: viewWindow.selectedNode
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
: Qt.vector3d(0, 0, 0)
globalOrientation: false globalOrientation: false
visible: selectedNode && btnScale.selected visible: selectedNode && btnScale.selected
view3D: overlayView view3D: overlayView
@@ -218,8 +214,6 @@ Window {
scale: autoScale.getScale(Qt.vector3d(7, 7, 7)) scale: autoScale.getScale(Qt.vector3d(7, 7, 7))
highlightOnHover: true highlightOnHover: true
targetNode: viewWindow.selectedNode targetNode: viewWindow.selectedNode
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
: Qt.vector3d(0, 0, 0)
globalOrientation: btnLocalGlobal.toggled globalOrientation: btnLocalGlobal.toggled
visible: selectedNode && btnRotate.selected visible: selectedNode && btnRotate.selected
view3D: overlayView view3D: overlayView
@@ -232,6 +226,7 @@ Window {
id: autoScale id: autoScale
view3D: overlayView view3D: overlayView
position: moveGizmo.scenePosition position: moveGizmo.scenePosition
orientation: moveGizmo.orientation
} }
} }

View File

@@ -37,12 +37,17 @@ Node {
readonly property bool dragging: arrowX.dragging || arrowY.dragging || arrowZ.dragging readonly property bool dragging: arrowX.dragging || arrowY.dragging || arrowZ.dragging
|| planeX.dragging || planeY.dragging || planeZ.dragging || planeX.dragging || planeY.dragging || planeZ.dragging
|| centerBall.dragging || centerBall.dragging
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
orientation: targetNode ? targetNode.orientation : Node.LeftHanded
signal positionCommit() signal positionCommit()
signal positionMove() signal positionMove()
Node { Node {
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation rotation: globalOrientation || !moveGizmo.targetNode ? Qt.vector3d(0, 0, 0)
: moveGizmo.targetNode.sceneRotation
rotationOrder: moveGizmo.targetNode ? moveGizmo.targetNode.rotationOrder : Node.YXZ
orientation: moveGizmo.orientation
Arrow { Arrow {
id: arrowX id: arrowX

View File

@@ -55,9 +55,13 @@ 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);
// Need separate variable as scenePos is reference to read-only property
var scenePosZ = scenePos.z
if (targetNode && targetNode.orientation === Node.RightHanded)
scenePosZ = -scenePosZ;
var scenePosWithOffset = Qt.vector3d(scenePos.x + offset.x, var scenePosWithOffset = Qt.vector3d(scenePos.x + offset.x,
scenePos.y + offset.y, scenePos.y + offset.y,
scenePos.z + offset.z); scenePosZ + 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;

View File

@@ -63,6 +63,8 @@ Model {
return; return;
_pointerPosPressed = mouseArea.mapPositionToScene(scenePos); _pointerPosPressed = mouseArea.mapPositionToScene(scenePos);
if (targetNode.orientation === Node.RightHanded)
_pointerPosPressed.z = -_pointerPosPressed.z;
var sp = targetNode.scenePosition; var sp = targetNode.scenePosition;
_targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
pressed(mouseArea); pressed(mouseArea);
@@ -71,9 +73,9 @@ Model {
function calcRelativeDistance(mouseArea, scenePos) function calcRelativeDistance(mouseArea, scenePos)
{ {
var scenePointerPos = mouseArea.mapPositionToScene(scenePos); var scenePointerPos = mouseArea.mapPositionToScene(scenePos);
return Qt.vector3d(scenePointerPos.x - _pointerPosPressed.x, if (targetNode.orientation === Node.RightHanded)
scenePointerPos.y - _pointerPosPressed.y, scenePointerPos.z = -scenePointerPos.z;
scenePointerPos.z - _pointerPosPressed.z); return scenePointerPos.minus(_pointerPosPressed);
} }
function handleDragged(mouseArea, scenePos) function handleDragged(mouseArea, scenePos)

View File

@@ -39,6 +39,9 @@ Node {
property real currentAngle property real currentAngle
property point currentMousePos property point currentMousePos
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
orientation: targetNode ? targetNode.orientation : Node.LeftHanded
signal rotateCommit() signal rotateCommit()
signal rotateChange() signal rotateChange()
@@ -69,7 +72,11 @@ Node {
} }
Node { Node {
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation id: rotNode
rotation: globalOrientation || !rotateGizmo.targetNode ? Qt.vector3d(0, 0, 0)
: rotateGizmo.targetNode.sceneRotation
rotationOrder: rotateGizmo.targetNode ? rotateGizmo.targetNode.rotationOrder : Node.YXZ
orientation: rotateGizmo.orientation
RotateRing { RotateRing {
id: rotRingX id: rotRingX
@@ -166,7 +173,14 @@ Node {
if (!rotateGizmo.targetNode) if (!rotateGizmo.targetNode)
return; return;
_targetPosOnScreen = view3D.mapFrom3DScene(rotateGizmo.targetNode.scenePosition); // Need to recreate vector as we need to adjust it and we can't do that on reference of
// scenePosition, which is read-only property
var scenePos = Qt.vector3d(rotateGizmo.targetNode.scenePosition.x,
rotateGizmo.targetNode.scenePosition.y,
rotateGizmo.targetNode.scenePosition.z);
if (rotateGizmo.targetNode && rotateGizmo.targetNode.orientation === Node.RightHanded)
scenePos.z = -scenePos.z
_targetPosOnScreen = view3D.mapFrom3DScene(scenePos);
_targetPosOnScreen.z = 0; _targetPosOnScreen.z = 0;
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0); _pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);

View File

@@ -77,7 +77,15 @@ Model {
if (!targetNode) if (!targetNode)
return; return;
_targetPosOnScreen = view3D.mapFrom3DScene(targetNode.scenePosition); // Need to recreate vector as we need to adjust it and we can't do that on reference of
// scenePosition, which is read-only property
var scenePos = Qt.vector3d(targetNode.scenePosition.x,
targetNode.scenePosition.y,
targetNode.scenePosition.z);
if (targetNode && targetNode.orientation === Node.RightHanded)
scenePos.z = -scenePos.z
_targetPosOnScreen = view3D.mapFrom3DScene(scenePos);
_targetPosOnScreen.z = 0; _targetPosOnScreen.z = 0;
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0); _pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);
_trackBall = angle < 0.1; _trackBall = angle < 0.1;

View File

@@ -38,11 +38,16 @@ Node {
|| planeX.dragging || planeY.dragging || planeZ.dragging || planeX.dragging || planeY.dragging || planeZ.dragging
|| centerMouseArea.dragging || centerMouseArea.dragging
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
orientation: targetNode ? targetNode.orientation : Node.LeftHanded
signal scaleCommit() signal scaleCommit()
signal scaleChange() signal scaleChange()
Node { Node {
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation
rotationOrder: scaleGizmo.targetNode ? scaleGizmo.targetNode.rotationOrder : Node.YXZ
orientation: scaleGizmo.orientation
ScaleRod { ScaleRod {
id: scaleRodX id: scaleRodX

View File

@@ -344,11 +344,17 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
QQuick3DNode *node, const QVector3D &pressPos, const QVector3D &currentPos, QQuick3DNode *node, const QVector3D &pressPos, const QVector3D &currentPos,
const QVector3D &nodePos, qreal prevAngle, bool trackBall) const QVector3D &nodePos, qreal prevAngle, bool trackBall)
{ {
const QVector3D cameraToNodeDir = getCameraToNodeDir(node); // Get camera to node direction in node orientation
QVector3D cameraToNodeDir = getCameraToNodeDir(node);
if (trackBall) { if (trackBall) {
// Only the distance in plane direction is relevant in trackball drag // Only the distance in plane direction is relevant in trackball drag
QVector3D dragDir = QVector3D::crossProduct(getNormal(), cameraToNodeDir).normalized(); QVector3D dragDir = QVector3D::crossProduct(getNormal(), cameraToNodeDir).normalized();
QVector3D screenDragDir = m_view3D->mapFrom3DScene(node->scenePosition() + dragDir); QVector3D scenePos = node->scenePosition();
if (node->orientation() == QQuick3DNode::RightHanded) {
scenePos.setZ(-scenePos.z());
dragDir = -dragDir;
}
QVector3D screenDragDir = m_view3D->mapFrom3DScene(scenePos + dragDir);
screenDragDir.setZ(0); screenDragDir.setZ(0);
dragDir = (screenDragDir - nodePos).normalized(); dragDir = (screenDragDir - nodePos).normalized();
const QVector3D pressToCurrent = (currentPos - pressPos); const QVector3D pressToCurrent = (currentPos - pressPos);
@@ -361,7 +367,9 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
qreal angle = qAcos(qreal(QVector3D::dotProduct(nodeToPress, nodeToCurrent))); qreal angle = qAcos(qreal(QVector3D::dotProduct(nodeToPress, nodeToCurrent)));
// Determine drag direction left/right // Determine drag direction left/right
const QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized(); QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized();
if (node->orientation() == QQuick3DNode::RightHanded)
dragNormal = -dragNormal;
angle *= QVector3D::dotProduct(QVector3D(0.f, 0.f, 1.f), dragNormal) < 0 ? -1.0 : 1.0; angle *= QVector3D::dotProduct(QVector3D(0.f, 0.f, 1.f), dragNormal) < 0 ? -1.0 : 1.0;
// Determine drag ring orientation relative to camera // Determine drag ring orientation relative to camera
@@ -392,7 +400,10 @@ void QmlDesigner::Internal::MouseArea3D::applyRotationAngleToNode(
{ {
if (!qFuzzyIsNull(angle)) { if (!qFuzzyIsNull(angle)) {
node->setRotation(startRotation); node->setRotation(startRotation);
node->rotate(qRadiansToDegrees(angle), getNormal(), QQuick3DNode::SceneSpace); QVector3D normal = getNormal();
if (orientation() != node->orientation())
normal.setZ(-normal.z());
node->rotate(qRadiansToDegrees(angle), normal, QQuick3DNode::SceneSpace);
} }
} }
@@ -407,6 +418,10 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo
const float *dataPtr(sceneTransform().data()); const float *dataPtr(sceneTransform().data());
QVector3D xAxis = QVector3D(-dataPtr[0], -dataPtr[1], -dataPtr[2]).normalized(); QVector3D xAxis = QVector3D(-dataPtr[0], -dataPtr[1], -dataPtr[2]).normalized();
QVector3D yAxis = QVector3D(-dataPtr[4], -dataPtr[5], -dataPtr[6]).normalized(); QVector3D yAxis = QVector3D(-dataPtr[4], -dataPtr[5], -dataPtr[6]).normalized();
if (node->orientation() == QQuick3DNode::RightHanded) {
xAxis = QVector3D(-xAxis.x(), -xAxis.y(), xAxis.z());
yAxis = QVector3D(-yAxis.x(), -yAxis.y(), yAxis.z());
}
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis); QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
@@ -596,11 +611,14 @@ QVector3D MouseArea3D::getCameraToNodeDir(QQuick3DNode *node) const
{ {
QVector3D dir; QVector3D dir;
if (qobject_cast<QQuick3DOrthographicCamera *>(m_view3D->camera())) { if (qobject_cast<QQuick3DOrthographicCamera *>(m_view3D->camera())) {
dir = m_view3D->camera()->cameraNode()->getDirection(); dir = -m_view3D->camera()->cameraNode()->getDirection();
// Camera direction has x and y flipped dir.setZ(-dir.z());
dir = QVector3D(-dir.x(), -dir.y(), dir.z());
} else { } else {
dir = (node->scenePosition() - m_view3D->camera()->scenePosition()).normalized(); QVector3D camPos = m_view3D->camera()->scenePosition();
QVector3D nodePos = node->scenePosition();
if (node->orientation() == QQuick3DNode::RightHanded)
nodePos.setZ(-nodePos.z());
dir = (node->scenePosition() - camPos).normalized();
} }
return dir; return dir;
} }