I ended up with combination of PinchArea
and MouseArea
:
import QtQml 2.2
import QtQuick 2.9
import QtQuick.Scene3D 2.0
import Qt3D.Core 2.9
import Qt3D.Extras 2.9
import Qt3D.Render 2.9
import Qt3D.Input 2.1
import Qt3D.Logic 2.0
import PanoEntity 1.0
import Utility 1.0
Item {
property url panorama
onPanoramaChanged: {
if (panorama.toString().length !== 0) {
if (panoEntity.setPanorama(panorama)) {
basicCamera.position = Qt.vector3d(0.0, 0.0, 0.0)
basicCamera.upVector = Qt.vector3d(0.0, 0.0, 1.0)
basicCamera.viewCenter = panoEntity.pano.dir
pinchArea.updateFov(defaultFov)
}
}
}
property Image previewImage
property real fovMin: 20.0
property real defaultFov: 60.0
property real fovMax: 90.0
property real sensitivity: 1.5
property real pinchSensitivity: 0.5
Scene3D {
id: scene3d
anchors.fill: parent
aspects: ["render", "input", "logic"]
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio // basicCamera.aspectRatio = width / height
multisample: true
Entity {
Camera {
id: basicCamera
projectionType: CameraLens.PerspectiveProjection
nearPlane: 0.1
farPlane: 2.0 * Math.SQRT2
}
RenderSettings {
id: renderSettings
renderPolicy: scene3d.visible ? RenderSettings.Always : RenderSettings.OnDemand
ForwardRenderer {
camera: basicCamera
clearColor: "transparent"
}
}
InputSettings {
id: inputSettings
}
components: [renderSettings, inputSettings]
PanoEntity {
id: panoEntity
MemoryBarrier {
waitFor: MemoryBarrier.All
}
}
}
}
PinchArea {
id: pinchArea
anchors.fill: parent
function updateFov(newFov) {
if (newFov > fovMax) {
newFov = fovMax
} else if (newFov < fovMin) {
newFov = fovMin
}
var eps = 1.0 / 60.0
if (Math.abs(basicCamera.fieldOfView - newFov) > eps) {
basicCamera.fieldOfView = newFov
zoomer.fov = newFov
}
}
function updatePinch(pinch) {
updateFov(basicCamera.fieldOfView * (1.0 + (pinch.previousScale - pinch.scale) * pinchSensitivity))
}
onPinchUpdated: {
updatePinch(pinch)
}
onPinchFinished: {
updatePinch(pinch)
}
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
property point startPoint
function updateView(mouse) {
basicCamera.pan((startPoint.x - mouse.x) * sensitivity * basicCamera.fieldOfView / width, Qt.vector3d(0.0, 0.0, 1.0))
basicCamera.tilt((mouse.y - startPoint.y) * sensitivity * basicCamera.fieldOfView / height)
startPoint = Qt.point(mouse.x, mouse.y)
}
onPressed: {
startPoint = Qt.point(mouse.x, mouse.y)
}
onPositionChanged: {
updateView(mouse)
}
onReleased: {
updateView(mouse)
}
}
}
Zoomer {
id: zoomer
fovMax: parent.fovMax
defaultFov: parent.defaultFov
fovMin: parent.fovMin
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 45
onFovChanged: {
pinchArea.updateFov(fov);
}
}
Shortcut {
context: Qt.WindowShortcut
enabled: scene3d.visible
sequence: StandardKey.Save
onActivated: {
panoEntity.pano.dir = basicCamera.viewCenter
panoEntity.pano.up = basicCamera.upVector
panoEntity.pano.version = 7
if (!panoEntity.updatePanorama()) {
console.log("Unable to update panorama %1".arg(panorama))
} else if (previewImage && Utility.fileExists(previewImage.source)) {
scene3d.grabToImage(function(grabResult) {
if (!grabResult.saveToFile(Utility.toLocalFile(previewImage.source))) {
console.log("Unable save preview to file: %1".arg(previewImage.source))
}
}, Qt.size(512, 512))
}
}
}
}