Meshroom/meshroom/ui/qml/Viewer3D/Viewer3D.qml
2019-09-11 10:09:27 +02:00

309 lines
10 KiB
QML

import QtQuick 2.7
import QtQuick.Controls 2.3
import QtQuick.Controls 1.4 as Controls1
import QtQuick.Layouts 1.3
import QtQml.Models 2.2
import QtQuick.Scene3D 2.0
import Qt3D.Core 2.1
import Qt3D.Render 2.1
import Qt3D.Extras 2.10
import Qt3D.Input 2.1 as Qt3DInput // to avoid clash with Controls2 Action
import MaterialIcons 2.2
import Controls 1.0
import Utils 1.0
FocusScope {
id: root
property int renderMode: 2
readonly property alias library: mediaLibrary
readonly property alias mainCamera: mainCamera
readonly property vector3d defaultCamPosition: Qt.vector3d(12.0, 10.0, -12.0)
readonly property vector3d defaultCamUpVector: Qt.vector3d(0.0, 1.0, 0.0)
readonly property vector3d defaultCamViewCenter: Qt.vector3d(0.0, 0.0, 0.0)
readonly property var viewpoint: _reconstruction.selectedViewpoint
readonly property bool doSyncViewpointCamera: Viewer3DSettings.syncViewpointCamera && (viewpoint && viewpoint.isReconstructed)
// functions
function resetCameraPosition() {
mainCamera.position = defaultCamPosition;
mainCamera.upVector = defaultCamUpVector;
mainCamera.viewCenter = defaultCamViewCenter;
}
function load(filepath) {
mediaLibrary.load(filepath);
}
/// View 'attribute' in the 3D Viewer. Media will be loaded if needed.
/// Returns whether the attribute can be visualized (matching type and extension).
function view(attribute) {
if( attribute.desc.type === "File"
&& Viewer3DSettings.supportedExtensions.indexOf(Filepath.extension(attribute.value)) > - 1 )
{
mediaLibrary.view(attribute);
return true;
}
return false;
}
/// Solo (i.e display only) the given attribute.
function solo(attribute) {
mediaLibrary.solo(mediaLibrary.find(attribute));
}
function clear() {
mediaLibrary.clear()
}
SystemPalette { id: activePalette }
Scene3D {
id: scene3D
anchors.fill: parent
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio // vs. UserAspectRatio
hoverEnabled: true // if true, will trigger positionChanged events in attached MouseHandler
aspects: ["logic", "input"]
focus: true
Keys.onPressed: {
if (event.key == Qt.Key_F) {
resetCameraPosition();
}
else if(Qt.Key_1 <= event.key && event.key <= Qt.Key_3)
{
Viewer3DSettings.renderMode = event.key - Qt.Key_1;
}
else {
event.accepted = false
}
}
Entity {
id: rootEntity
Camera {
id: mainCamera
projectionType: CameraLens.PerspectiveProjection
enabled: cameraSelector.camera == mainCamera
fieldOfView: 45
nearPlane : 0.01
farPlane : 10000.0
position: defaultCamPosition
upVector: defaultCamUpVector
viewCenter: defaultCamViewCenter
aspectRatio: width/height
Behavior on viewCenter {
Vector3dAnimation { duration: 250 }
}
Behavior on position {
Vector3dAnimation { duration: 250 }
}
// Scene light, attached to the camera
Entity {
components: [
PointLight {
color: "white"
}
]
}
}
ViewpointCamera {
id: viewpointCamera
enabled: cameraSelector.camera === camera
viewpoint: root.viewpoint
camera.aspectRatio: width/height
}
TrackballGizmo {
beamRadius: 4.0/root.height
alpha: cameraController.moving ? 1.0 : 0.7
enabled: Viewer3DSettings.displayGizmo && cameraSelector.camera == mainCamera
xColor: Colors.red
yColor: Colors.green
zColor: Colors.blue
centerColor: Colors.sysPalette.highlight
transform: Transform {
translation: mainCamera.viewCenter
scale: 0.15 * mainCamera.viewCenter.minus(mainCamera.position).length()
}
}
DefaultCameraController {
id: cameraController
enabled: cameraSelector.camera == mainCamera
windowSize {
width: root.width
height: root.height
}
rotationSpeed: 16
trackballSize: 0.9
camera: mainCamera
focus: scene3D.activeFocus
onMousePressed: {
scene3D.forceActiveFocus()
if(mouse.button == Qt.LeftButton)
{
if(!doubleClickTimer.running)
doubleClickTimer.restart()
}
else
doubleClickTimer.stop()
}
onMouseReleased: {
if(moving)
return
if(!moved && 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 {
pickingSettings.pickMethod: PickingSettings.PrimitivePicking // enables point/edge/triangle picking
pickingSettings.pickResultMode: PickingSettings.NearestPick
renderPolicy: RenderSettings.Always
activeFrameGraph: RenderSurfaceSelector {
// Use the whole viewport
Viewport {
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
CameraSelector {
id: cameraSelector
camera: doSyncViewpointCamera ? viewpointCamera.camera : mainCamera
FrustumCulling {
ClearBuffers {
clearColor: "transparent"
buffers : ClearBuffers.ColorDepthBuffer
RenderStateSet {
renderStates: [
PointSize {
sizeMode: Viewer3DSettings.fixedPointSize ? PointSize.Fixed : PointSize.Programmable
value: Viewer3DSettings.pointSize
},
DepthTest { depthFunction: DepthTest.Less }
]
}
}
}
}
}
}
},
Qt3DInput.InputSettings { }
]
MediaLibrary {
id: mediaLibrary
renderMode: Viewer3DSettings.renderMode
// Picking to set focus point (camera view center)
// Only activate it when a double click may happen or when the 'Control' key is pressed
pickingEnabled: cameraController.pickingActive || doubleClickTimer.running
components: [
Transform {
id: transform
}
]
onPressed: {
if(pick.button == Qt.LeftButton)
{
mainCamera.viewCenter = pick.worldIntersection;
}
doubleClickTimer.stop();
}
}
Locator3D { enabled: Viewer3DSettings.displayOrigin }
Grid3D { enabled: Viewer3DSettings.displayGrid }
}
}
// Image overlay when navigating reconstructed cameras
Loader {
id: imageOverlayLoader
anchors.fill: parent
active: doSyncViewpointCamera
visible: Viewer3DSettings.showViewpointImageOverlay
sourceComponent: ImageOverlay {
id: imageOverlay
source: root.viewpoint.undistortedImageSource
imageRatio: root.viewpoint.orientedImageSize.width / root.viewpoint.orientedImageSize.height
uvCenterOffset: root.viewpoint.uvCenterOffset
showFrame: Viewer3DSettings.showViewpointImageFrame
imageOpacity: Viewer3DSettings.viewpointImageOverlayOpacity
}
}
// Media loading overlay
// (Scene3D is frozen while a media is being loaded)
Rectangle {
anchors.fill: parent
visible: mediaLibrary.loading
color: Qt.darker(Colors.sysPalette.mid, 1.2)
opacity: 0.6
BusyIndicator {
anchors.centerIn: parent
running: parent.visible
}
}
// Rendering modes
FloatingPane {
anchors.bottom: parent.bottom
padding: 4
Row {
Repeater {
model: Viewer3DSettings.renderModes
delegate: MaterialToolButton {
text: modelData["icon"]
ToolTip.text: modelData["name"] + " (" + (index+1) + ")"
font.pointSize: 11
onClicked: Viewer3DSettings.renderMode = index
checked: Viewer3DSettings.renderMode === index
checkable: !checked // hack to disabled check on toggle
}
}
}
}
// Menu
Menu {
id: contextMenu
MenuItem {
text: "Fit All"
onTriggered: mainCamera.viewAll()
}
MenuItem {
text: "Reset View"
onTriggered: resetCameraPosition()
}
}
}