Revision control

Copy as Markdown

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick3D
import QtQuick3D.Helpers
import QtQuick3D.Xr
pragma ComponentBehavior: Bound
XrView {
id: xrView
referenceSpace: XrView.ReferenceSpaceStage
depthSubmissionEnabled: true
property list<color> colorTable: [Qt.rgba(1, 0, 1, 1), // magenta
Qt.rgba(0, 1, 0, 1), // green
Qt.rgba(0, 0.5, 0.5, 1), // darkCyan
Qt.rgba(0.5, 0.5, 0, 1), // darkYellow
Qt.rgba(0, 0, 1, 1), // blue
Qt.rgba(1, 0, 0, 1), // red
Qt.rgba(0.5, 0, 0, 1), // darkRed
Qt.rgba(1, 1, 0, 1)] // yellow
property list<color> extraColorTable: [Qt.rgba(0.5, 0.5, 0.5, 1), // dark gray
Qt.rgba(0.9, 0.9, 0.7, 1)] // beige
function colorForClassification(index) {
return colorTable[index > 0 && index < colorTable.length ? index : 0]
}
function colorForClassificationOther(classificationName) {
const index = ["screen", "storage"].indexOf(classificationName.toLowerCase())
return extraColorTable[index > 0 && index < extraColorTable.length ? index : 0]
}
function anchorColor(anchor) {
const classification = anchor.classification
if (classification === XrSpatialAnchor.Other)
return colorForClassificationOther(anchor.classificationString)
else
return colorForClassification(classification)
}
property bool preferPassthrough: true
passthroughEnabled: passthroughSupported && preferPassthrough
XrErrorDialog { id: err }
onInitializeFailed: (errorString) => {
console.log("===================>>>>>>" + errorString)
err.run("XRView", errorString)
}
environment: SceneEnvironment {
id: sceneEnvironment
skyMaterial: ProceduralSkyMaterial {}
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.High
backgroundMode: xrView.passthroughEnabled ? SceneEnvironment.Transparent : SceneEnvironment.Color
clearColor: "skyblue"
probeHorizon: 0.5
}
xrOrigin: XrOrigin {
id: theOrigin
XrController {
id: rightController
controller: XrController.RightController
poseSpace: XrController.AimPose
XrInputAction {
hand: XrInputAction.RightHand
actionId: [XrInputAction.Button2Pressed, XrInputAction.MiddleFingerPinch]
onTriggered: xrView.preferPassthrough = !xrView.preferPassthrough
}
XrInputAction {
hand: XrInputAction.RightHand
actionId: [XrInputAction.Button1Pressed]
onTriggered: {
spatialAnchors.model.requestSceneCapture()
}
}
onRotationChanged: {
const pickResult = xrView.rayPick(scenePosition, forward)
if (pickResult.hitType === PickResult.Model) {
pickRay.hit = true
pickRay.length = pickResult.distance
movableObject.move(pickResult.scenePosition, pickResult.sceneNormal)
movableObject.visible = true
// qmllint disable missing-property
const info = pickResult.objectHit?.anchorInfo
// qmllint enable missing-property
labelNode.anchorInfo = info ? info : "(unknown)"
} else {
pickRay.hit = false
pickRay.length = 50
labelNode.anchorInfo = "(no anchor)"
}
}
Node {
id: pickRay
property real length: 50
property bool hit: false
z: -length/2
Model {
eulerRotation.x: 90
scale: Qt.vector3d(0.02, pickRay.length/100, 0.02)
source: "#Cylinder"
materials: PrincipledMaterial { baseColor: pickRay.hit ? "green" : "gray" }
opacity: 0.5
}
}
}
}
Node {
id: movableObject
// This object is positioned on anchors where the ray hits
visible: false
function move(pos: vector3d, normal: vector3d) {
const rot = Quaternion.lookAt(pos, pos.plus(normal));
position = pos
rotation = rot
}
Model {
scale: Qt.vector3d(0.5, 0.05, 0.5)
eulerRotation.x: 90
z: -2.5
source: "#Cylinder"
materials: PrincipledMaterial {
baseColor: "red"
roughness: 0.5
}
}
}
//! [label]
Node {
id: labelNode
position: rightController.position
rotation: rightController.rotation
property int numAnchors: spatialAnchors.count
property string anchorInfo: "(no anchor)"
Node {
y: 15
x: -15
scale: Qt.vector3d(0.1, 0.1, 0.1)
Rectangle {
width: 300
height: 100
color: Qt.rgba(1,0.9,0.8,0.7)
radius: 10
border.width: 2
border.color: "blue"
Text {
anchors.fill: parent
anchors.margins: 10
textFormat: Text.StyledText
text: "Total anchors: " + labelNode.numAnchors + "<br>" + "Selected: " + labelNode.anchorInfo + "<br>" + "Press A to Capture/Update anchors"
}
}
}
}
//! [label]
//! [repeater]
Repeater3D {
id: spatialAnchors
model: XrSpatialAnchorListModel {
}
delegate: Node {
id: anchorNode
required property XrSpatialAnchor anchor
required property int index
position: anchor.position
rotation: anchor.rotation
Model {
pickable: true
z: anchorNode.anchor.has3DBounds ? anchorNode.anchor.offset3D.z / 2 * 100 : 0 // Position is center of 2D surface also for 3D anchors
scale: anchorNode.anchor.has3DBounds ? anchorNode.anchor.extent3D : Qt.vector3d(anchorNode.anchor.extent2D.x, anchorNode.anchor.extent2D.y, 0.01)
materials: PrincipledMaterial {
// Make anchor objects invisible in passthrough mode
baseColor: xrView.passthroughEnabled ? Qt.rgba(0, 0, 0, 0) : anchorColor(anchor)
alphaMode: xrView.passthroughEnabled ? PrincipledMaterial.Blend : PrincipledMaterial.Opaque
roughness: 0.7
}
source: anchorNode.anchor.has3DBounds ? "#Cube" : "#Rectangle"
property string anchorInfo: "anchor #" + anchorNode.index + ", " + anchorNode.anchor.classificationString
}
Model {
// Visualize anchor orientation
materials: PrincipledMaterial {
baseColor: anchorNode.anchor.has3DBounds ? anchorNode.anchor.has2DBounds ? "green" : "red" : "blue"
}
scale: Qt.vector3d(0.05, 0.05, 0.05)
source: "#Cube"
Model {
materials: PrincipledMaterial {
baseColor: "black"
}
scale: Qt.vector3d(0.1, 3, 0.1)
source: "#Cube"
y: 150
}
Model {
materials: PrincipledMaterial {
baseColor: "white"
}
scale: Qt.vector3d(3, 0.1, 0.1)
source: "#Cube"
x: 150
}
}
visible: anchor.has2DBounds || anchor.has3DBounds
}
}
//! [repeater]
}