mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-26 21:17:29 +02:00
* 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
258 lines
8.4 KiB
QML
258 lines
8.4 KiB
QML
import QtQuick 2.7
|
|
import QtQuick.Controls 2.3
|
|
import QtQuick.Layouts 1.3
|
|
import QtQuick.Scene3D 2.0
|
|
import Qt3D.Core 2.1
|
|
import Qt3D.Render 2.1
|
|
import Qt3D.Input 2.1 as Qt3DInput // to avoid clash with Controls2 Action
|
|
|
|
|
|
FocusScope {
|
|
id: root
|
|
|
|
property alias status: scene.status
|
|
property alias source: modelLoader.source
|
|
readonly property alias loading: modelLoader.loading
|
|
|
|
// functions
|
|
function resetCameraCenter() {
|
|
mainCamera.viewCenter = Qt.vector3d(0.0, 0.0, 0.0);
|
|
mainCamera.upVector = Qt.vector3d(0.0, 1.0, 0.0);
|
|
}
|
|
|
|
function resetCameraPosition() {
|
|
mainCamera.position = Qt.vector3d(28.0, 21.0, 28.0);
|
|
mainCamera.upVector = Qt.vector3d(0.0, 1.0, 0.0);
|
|
mainCamera.viewCenter = Qt.vector3d(0.0, 0.0, 0.0);
|
|
}
|
|
|
|
function findChildrenByProperty(node, propertyName, container)
|
|
{
|
|
if(!node || !node.childNodes)
|
|
return;
|
|
for(var i=0; i < node.childNodes.length; ++i)
|
|
{
|
|
var childNode = node.childNodes[i];
|
|
if(!childNode)
|
|
continue;
|
|
if(childNode[propertyName] !== undefined)
|
|
container.push(childNode);
|
|
else
|
|
findChildrenByProperty(childNode, propertyName, container)
|
|
}
|
|
}
|
|
|
|
function unmirrorTextures(rootEntity)
|
|
{
|
|
var materials = [];
|
|
findChildrenByProperty(rootEntity, "diffuse", materials);
|
|
|
|
var textures = [];
|
|
materials.forEach(function(mat){
|
|
mat["diffuse"].magnificationFilter = Texture.Linear;
|
|
findChildrenByProperty(mat["diffuse"], "mirrored", textures)
|
|
})
|
|
|
|
//console.log(textures)
|
|
textures.forEach(function(tex){
|
|
//console.log("Unmirroring: " + tex.source)
|
|
tex.mirrored = false
|
|
})
|
|
}
|
|
|
|
function clear()
|
|
{
|
|
source = 'no_file'
|
|
}
|
|
|
|
Scene3D {
|
|
id: scene3D
|
|
anchors.fill: parent
|
|
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio // vs. UserAspectRatio
|
|
hoverEnabled: false // if true, will trigger positionChanged events in attached MouseHandler
|
|
aspects: ["logic", "input"]
|
|
focus: true
|
|
Keys.onPressed: {
|
|
if (event.key == Qt.Key_F) {
|
|
resetCameraCenter();
|
|
resetCameraPosition();
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
|
|
Entity {
|
|
id: rootEntity
|
|
Camera {
|
|
id: mainCamera
|
|
projectionType: CameraLens.PerspectiveProjection
|
|
fieldOfView: 45
|
|
nearPlane : 0.1
|
|
farPlane : 1000.0
|
|
position: Qt.vector3d(28.0, 21.0, 28.0)
|
|
upVector: Qt.vector3d(0.0, 1.0, 0.0)
|
|
viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
|
|
aspectRatio: width/height
|
|
|
|
Behavior on viewCenter {
|
|
Vector3dAnimation { duration: 250 }
|
|
}
|
|
}
|
|
|
|
DefaultCameraController {
|
|
id: cameraController
|
|
camera: mainCamera
|
|
onMousePressed: {
|
|
scene3D.forceActiveFocus()
|
|
if(mouse.button == Qt.LeftButton)
|
|
{
|
|
if(!doubleClickTimer.running)
|
|
doubleClickTimer.restart()
|
|
}
|
|
else
|
|
doubleClickTimer.stop()
|
|
}
|
|
onMouseReleased: {
|
|
if(moving)
|
|
return
|
|
if(mouse.button == Qt.RightButton)
|
|
{
|
|
contextMenu.popup()
|
|
}
|
|
}
|
|
|
|
// 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: [
|
|
RenderSettings {
|
|
// To avoid performance drops, picking is only enabled under certain circumstances (see ObjectPicker below)
|
|
pickingSettings.pickMethod: PickingSettings.TrianglePicking
|
|
pickingSettings.pickResultMode: PickingSettings.NearestPick
|
|
renderPolicy: RenderSettings.Always
|
|
activeFrameGraph: Viewport {
|
|
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
|
|
RenderSurfaceSelector {
|
|
CameraSelector {
|
|
id: cameraSelector
|
|
camera: mainCamera
|
|
//FrustumCulling {
|
|
ClearBuffers {
|
|
buffers : ClearBuffers.ColorDepthBuffer
|
|
clearColor: Qt.rgba(0, 0, 0, 0.1)
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
Qt3DInput.InputSettings {
|
|
eventSource: _window
|
|
enabled: true
|
|
}
|
|
]
|
|
|
|
Entity {
|
|
id: modelLoader
|
|
property string source
|
|
// SceneLoader status is not reliable when loading a 3D file
|
|
property bool loading
|
|
onSourceChanged: loading = true
|
|
|
|
components: [scene, transform, picker]
|
|
|
|
// ObjectPicker used for view re-centering
|
|
ObjectPicker {
|
|
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
|
|
onPressed: {
|
|
if(pick.button == Qt.LeftButton)
|
|
mainCamera.viewCenter = pick.worldIntersection
|
|
doubleClickTimer.stop()
|
|
}
|
|
}
|
|
|
|
Transform {
|
|
id: transform
|
|
}
|
|
|
|
SceneLoader {
|
|
id: scene
|
|
source: Qt.resolvedUrl(modelLoader.source)
|
|
onStatusChanged: {
|
|
if(scene.status != SceneLoader.Loading)
|
|
modelLoader.loading = false;
|
|
if(scene.status == SceneLoader.Ready)
|
|
{
|
|
unmirrorTextures(parent);
|
|
}
|
|
}
|
|
}
|
|
Locator3D { enabled: locatorCheckBox.checked}
|
|
}
|
|
|
|
Grid3D { enabled: gridCheckBox.checked }
|
|
|
|
}
|
|
}
|
|
|
|
Pane {
|
|
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
|
Column {
|
|
spacing: 5
|
|
Row {
|
|
spacing: 4
|
|
Slider { width: 100; from: -180; to: 180; onPositionChanged: transform.rotationX = value}
|
|
Label { text: "RX" }
|
|
}
|
|
|
|
Row {
|
|
spacing: 4
|
|
Slider { width: 100; from: -180; to: 180; onPositionChanged: transform.rotationY = value }
|
|
Label { text: "RY" }
|
|
}
|
|
|
|
Row {
|
|
spacing: 4
|
|
Slider { width: 100; from: -180; to: 180; onPositionChanged: transform.rotationZ = value }
|
|
Label { text: "RZ" }
|
|
}
|
|
|
|
Row {
|
|
spacing: 4
|
|
Slider { width: 100; from: 1; to: 10; onPositionChanged: transform.scale = value }
|
|
Label { text: "Scale" }
|
|
}
|
|
}
|
|
}
|
|
|
|
Pane {
|
|
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
|
anchors.right: parent.right
|
|
Column {
|
|
CheckBox { id: gridCheckBox; text: "Grid"; checked: true }
|
|
CheckBox { id: locatorCheckBox; text: "Locator"; checked: true }
|
|
}
|
|
}
|
|
|
|
// Menu
|
|
Menu {
|
|
id: contextMenu
|
|
MenuItem {
|
|
text: "View All"
|
|
onTriggered: mainCamera.viewAll()
|
|
}
|
|
MenuItem {
|
|
text: "Reset View"
|
|
onTriggered: resetCameraPosition()
|
|
}
|
|
}
|
|
}
|