[ui] Viewer3D: DefaultCameraController + better double click handling

* add DefaultCameraController: 
   * mouse-only navigation
   * keyboard modifiers fallbacks for view re-centering (Ctrl+LeftClick) and fast zooming (Alt+RightClick)
* improved double click handling for 3D Object Picking
  * moved logic/Timer to the CameraController
  * always use TrianglePicking but only activate the ObjectPicker when necessary
This commit is contained in:
Yann Lanthony 2017-12-12 19:10:18 +01:00
parent 886ded7f19
commit ecc376e3b6
3 changed files with 172 additions and 27 deletions

View file

@ -0,0 +1,140 @@
import QtQuick 2.7
import Qt3D.Core 2.1
import Qt3D.Render 2.1
import Qt3D.Input 2.1
import Qt3D.Logic 2.0
import QtQml 2.2
Entity {
id: root
property Camera camera
property real translateSpeed: 75.0
property real tiltSpeed: 500.0
property real panSpeed: 500.0
property bool moving: pressed || actionAlt.active
readonly property alias controlPressed: actionControl.active
readonly property alias pressed: mouseHandler._pressed
signal mousePressed(var mouse)
signal mouseReleased(var mouse)
signal mouseClicked(var mouse)
signal mouseWheeled(var wheel)
signal mouseDoubleClicked(var mouse)
KeyboardDevice { id: keyboardSourceDevice }
MouseDevice { id: mouseSourceDevice }
MouseHandler {
id: mouseHandler
property bool _pressed
sourceDevice: mouseSourceDevice
onPressed: { _pressed = true; mousePressed(mouse) }
onReleased: { _pressed = false; mouseReleased(mouse) }
onClicked: mouseClicked(mouse)
onDoubleClicked: mouseDoubleClicked(mouse)
onWheel: {
var d = (root.camera.viewCenter.minus(root.camera.position)).length() * 0.2;
var tz = (wheel.angleDelta.y / 120) * d;
root.camera.translate(Qt.vector3d(0, 0, tz), Camera.DontTranslateViewCenter)
}
}
LogicalDevice {
id: cameraControlDevice
actions: [
Action {
id: actionLMB
inputs: [
ActionInput {
sourceDevice: mouseSourceDevice
buttons: [MouseEvent.LeftButton]
}
]
},
Action {
id: actionRMB
inputs: [
ActionInput {
sourceDevice: mouseSourceDevice
buttons: [MouseEvent.RightButton]
}
]
},
Action {
id: actionMMB
inputs: [
ActionInput {
sourceDevice: mouseSourceDevice
buttons: [MouseEvent.MiddleButton]
}
]
},
Action {
id: actionControl
inputs: [
ActionInput {
sourceDevice: keyboardSourceDevice
buttons: [Qt.Key_Control]
}
]
},
Action {
id: actionAlt
inputs: [
ActionInput {
sourceDevice: keyboardSourceDevice
buttons: [Qt.Key_Alt]
}
]
}
]
axes: [
Axis {
id: axisMX
inputs: [
AnalogAxisInput {
sourceDevice: mouseSourceDevice
axis: MouseDevice.X
}
]
},
Axis {
id: axisMY
inputs: [
AnalogAxisInput {
sourceDevice: mouseSourceDevice
axis: MouseDevice.Y
}
]
}
]
}
components: [
FrameAction {
onTriggered: {
if(actionLMB.active) { // rotate
var rx = -axisMX.value;
var ry = -axisMY.value;
root.camera.panAboutViewCenter(root.panSpeed * rx * dt, Qt.vector3d(0,1,0))
root.camera.tiltAboutViewCenter(root.tiltSpeed * ry * dt)
return;
}
if(actionMMB.active) { // translate
var d = (root.camera.viewCenter.minus(root.camera.position)).length() * 0.03;
var tx = axisMX.value * root.translateSpeed * d;
var ty = axisMY.value * root.translateSpeed * d;
root.camera.translate(Qt.vector3d(-tx, -ty, 0).times(dt))
return;
}
if(actionAlt.active && actionRMB.active) { // zoom with alt + RMD
var d = (root.camera.viewCenter.minus(root.camera.position)).length() * 0.1;
var tz = axisMX.value * root.translateSpeed * d;
root.camera.translate(Qt.vector3d(0, 0, tz).times(dt), Camera.DontTranslateViewCenter)
return;
}
}
}
]
}

View file

@ -98,32 +98,42 @@ FocusScope {
} }
} }
MayaCameraController { DefaultCameraController {
id: cameraController id: cameraController
camera: mainCamera camera: mainCamera
onMousePressed: { onMousePressed: {
mouse.accepted = false
scene3D.forceActiveFocus() scene3D.forceActiveFocus()
if(mouse.button == Qt.LeftButton)
{
if(!doubleClickTimer.running)
doubleClickTimer.restart()
}
else
doubleClickTimer.stop()
} }
onMouseReleased: { onMouseReleased: {
if(moving) if(moving)
return; return
switch(mouse.button) { if(mouse.button == Qt.RightButton)
case Qt.LeftButton: {
break; contextMenu.popup()
case Qt.RightButton:
contextMenu.x = mouse.x;
contextMenu.y = mouse.y;
contextMenu.open();
break;
} }
} }
// Manually handle double click to activate object picking
// for camera re-centering only during a short amount of time
Timer {
id: doubleClickTimer
running: false
interval: 300
}
} }
components: [ components: [
RenderSettings { RenderSettings {
// To avoid performance drop, only pick triangles when not moving the camera // To avoid performance drops, picking is only enabled under certain circumstances (see ObjectPicker below)
pickingSettings.pickMethod: cameraController.moving ? PickingSettings.BoundingVolumePicking : PickingSettings.TrianglePicking pickingSettings.pickMethod: PickingSettings.TrianglePicking
pickingSettings.pickResultMode: PickingSettings.NearestPick
renderPolicy: RenderSettings.Always renderPolicy: RenderSettings.Always
activeFrameGraph: Viewport { activeFrameGraph: Viewport {
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0) normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
@ -156,23 +166,17 @@ FocusScope {
components: [scene, transform, picker] components: [scene, transform, picker]
// ObjectPicker used for view re-centering
ObjectPicker { ObjectPicker {
id: picker id: picker
// Triangle picking is expensive
// Only activate it when a double click may happen or when the 'Control' key is pressed
enabled: cameraController.controlPressed || doubleClickTimer.running
hoverEnabled: false hoverEnabled: false
onPressed: { onPressed: {
if(Qt.LeftButton & pick.buttons) if(pick.button == Qt.LeftButton)
{ mainCamera.viewCenter = pick.worldIntersection
if(!doubleClickTimer.running) doubleClickTimer.stop()
doubleClickTimer.start()
else
mainCamera.viewCenter = pick.worldIntersection
}
}
Timer {
id: doubleClickTimer
running: false
interval: 400
} }
} }
@ -239,7 +243,7 @@ FocusScope {
} }
} }
// menus // Menu
Menu { Menu {
id: contextMenu id: contextMenu
MenuItem { MenuItem {

View file

@ -2,6 +2,7 @@ module Viewer
Viewer2D 1.0 Viewer2D.qml Viewer2D 1.0 Viewer2D.qml
Viewer3D 1.0 Viewer3D.qml Viewer3D 1.0 Viewer3D.qml
DefaultCameraController 1.0 DefaultCameraController.qml
MayaCameraController 1.0 MayaCameraController.qml MayaCameraController 1.0 MayaCameraController.qml
Locator3D 1.0 Locator3D.qml Locator3D 1.0 Locator3D.qml
Grid3D 1.0 Grid3D.qml Grid3D 1.0 Grid3D.qml