如何为Qt3D
Camera
的FOV实现两指捏合手势处理?
有
FirstPersonCameraController
和 OrbitCameraController
相机控制器处理鼠标/触摸板事件。后者甚至具有 zoomLimit
属性,但其含义不是我缩放场景所需的(从立方体贴图内部,相机位置固定为 (0, 0, 0)
)。我用的是前一种。它可以正确处理鼠标拖动和单指触摸事件,但不能处理两指捏合手势。
我可以通过简单的方式自定义
PinchArea
来与Qt3D的Camera
交互吗?或者 Qt Quick 的 API 在这个意义上与 Qt3D 的 API 是正交的?
使用 PinchArea 的捏更新事件来查找有关捏合的信息:根据文档
捏合参数提供有关捏合手势的信息, 包括捏合的规模、中心和角度。这些值 仅反映自当前手势开始以来的变化,并且 因此不受最小和最大限制的限制 捏属性。
所以你应该能够做类似的事情:
Camera {
id: myCamera
}
PinchArea {
onPinchUpdated: {
myCamera.fieldOfView = pinch.scale*someFactor
}
}
这可以在您拥有的任何可以访问捏合和相机的自定义 QML 中完成。 如果它是自定义脚本,您始终可以将相机作为属性传递
property Camera myCamera
我最终得到了
PinchArea
和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))
}
}
}
}