Revision control
Copy as Markdown
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick3D
import QtQuick3D.Helpers
import QtQuick.Controls
Window {
visible: true
width: 1280
height: 720
title: qsTr("Instanced Picking")
View3D {
id: viewport
anchors.fill: parent
environment: SceneEnvironment {
clearColor: "gray"
backgroundMode: SceneEnvironment.Color
}
Node {
PerspectiveCamera {
z: 1000
}
PropertyAnimation on eulerRotation.y {
from: 0
to: 360
running: true
duration: 57000
loops: -1
}
}
SpotLight {
position: Qt.vector3d(0, 800, 0)
eulerRotation.x: -90
coneAngle: 60
color: Qt.rgba(1.0, 1.0, 0.1, 1.0)
brightness: 50
castsShadow: true
shadowMapQuality: Light.ShadowMapQualityHigh
ambientColor: "#777"
shadowFactor: 90
}
RandomInstancing {
id: randomWithData
instanceCount: 1000
position: InstanceRange {
from: Qt.vector3d(-500, -400, -500)
to: Qt.vector3d(500, 400, 500)
}
scale: InstanceRange {
from: Qt.vector3d(0.1, 0.1, 0.1)
to: Qt.vector3d(0.7, 0.7, 0.7)
proportional: true
}
rotation: InstanceRange {
from: Qt.vector3d(0, 0, 0)
to: Qt.vector3d(360, 360, 360)
}
color: InstanceRange {
from: Qt.rgba(0.1, 0.1, 0.1, 1.0)
to: Qt.rgba(1, 1, 1, 1.0)
}
// instancedMaterial custom data: METALNESS, ROUGHNESS, FRESNEL_POWER, SPECULAR_AMOUNT
customData: InstanceRange {
from: Qt.vector4d(0, 0, 0, 0)
to: Qt.vector4d(1, 1, 5, 1)
}
}
FileInstancing {
id: fileInstancing
source: "test.xml"
}
CustomMaterial {
id: instancedMaterial
shadingMode: CustomMaterial.Shaded
fragmentShader: "material.frag"
vertexShader: "material.vert"
property color uDiffuse: "lightgray"
}
Model {
id: cubeModel
source: "#Cube"
instancing: randomWithData
materials: PrincipledMaterial {
baseColor: "white"
}
PropertyAnimation on eulerRotation.x {
from: 0
to: 360
duration: 5000
loops: -1
}
pickable: true
Model {
id: sphereModel
source: "#Sphere"
instancing: parent.instancing
instanceRoot: parent
pickable: true
property real scaleFactor: 0.5
scale: Qt.vector3d(scaleFactor, scaleFactor, scaleFactor);
position: Qt.vector3d(-50, -50, -50)
materials: instancedMaterial
SequentialAnimation on scaleFactor {
PauseAnimation {duration: 3000}
NumberAnimation {from: 0.5; to: 1.5; duration: 200}
NumberAnimation {from: 1.5; to: 0.5; duration: 200}
loops: -1
}
} // sphereModel
} // cubeModel
// For reference: this is how to do it using the InstanceModel
// Repeater3D {
// model: TestModel { instancingTable: randomWithData }
// }
// Model {
// id: delegate
// source: "#Cube"
// pickable: true
// property int instanceIndex: index
// position: modelPosition
// scale: modelScale
// rotation: modelRotation
// materials: [
// PrincipledMaterial {
// baseColor: modelColor
// }
// ]
// opacity: 0.5
// }
// }
// The old way of doing things: using an InstanceRepeater
// InstanceRepeater {
// instancingTable: randomWithData
// Model {
// id: delegate
// source: "#Cube"
// pickable: true
// property int instanceIndex: index // used for indexLabel.text
// property color instanceColor: modelColor
// opacity: 0
// }
// }
//
} // View3D
MouseArea {
anchors.fill: viewport
//! [mouse area]
onClicked: (mouse) => {
// Get screen coordinates of the click
positionLabel.text = "(" + mouse.x + ", " + mouse.y + ")"
//! [pick result]
var result = viewport.pick(mouse.x, mouse.y);
//! [pick result]
//! [pick specifics]
if (result.objectHit) {
var pickedObject = result.objectHit;
// Get picked model index
indexLabel.text = result.instanceIndex
// Get other pick specifics
uvPosition.text = "("
+ result.uvPosition.x.toFixed(2) + ", "
+ result.uvPosition.y.toFixed(2) + ")";
distance.text = result.distance.toFixed(2);
scenePosition.text = "("
+ result.scenePosition.x.toFixed(2) + ", "
+ result.scenePosition.y.toFixed(2) + ", "
+ result.scenePosition.z.toFixed(2) + ")";
localPosition.text = "("
+ result.position.x.toFixed(2) + ", "
+ result.position.y.toFixed(2) + ", "
+ result.position.z.toFixed(2) + ")";
colorRect.color = (pickedObject === cubeModel) ? randomWithData.instanceColor(result.instanceIndex) : "transparent"
//! [pick specifics]
} else {
indexLabel.text = "None";
uvPosition.text = "";
distance.text = "";
scenePosition.text = "";
localPosition.text = "";
colorRect.color = "transparent"
}
}
}
Row {
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.leftMargin: 8
spacing: 10
Column {
Label {
color: "white"
font.pointSize: 14
text: "Screen Position:"
}
Label {
color: "white"
font.pointSize: 14
text: "Index:"
}
Label {
color: "white"
font.pointSize: 14
text: "Color:"
}
Label {
color: "white"
font.pointSize: 14
text: "UV Position:"
}
Label {
color: "white"
font.pointSize: 14
text: "Distance:"
}
Label {
color: "white"
font.pointSize: 14
text: "World Position:"
}
Label {
color: "white"
font.pointSize: 14
text: "Local Position:"
}
}
Column {
Label {
id: positionLabel
color: "white"
font.pointSize: 14
}
Label {
id: indexLabel
color: "white"
font.pointSize: 14
}
Rectangle {
id: colorRect
height: indexLabel.height
width: indexLabel.width
color: "transparent"
}
Label {
id: uvPosition
color: "white"
font.pointSize: 14
}
Label {
id: distance
color: "white"
font.pointSize: 14
}
Label {
id: scenePosition
color: "white"
font.pointSize: 14
}
Label {
id: localPosition
color: "white"
font.pointSize: 14
}
}
}
}