// Copyright (C) 2020 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 import InstancingTest Window { visible: true width: 1280 height: 720 title: qsTr("Instanced Rendering") View3D { id: viewport anchors.fill: parent environment: SceneEnvironment { clearColor: "gray" backgroundMode: SceneEnvironment.Color } Node { PerspectiveCamera { z: 1000 SequentialAnimation on z { running: false loops: -1 PauseAnimation { duration: 4000 } NumberAnimation { from: 5000 to: 0 duration: 15000 } PauseAnimation { duration: 300 } NumberAnimation { from: 0 to: 5000 duration: 5000 } } } PropertyAnimation on eulerRotation.y { from: 0 to: 360 running: false duration: 17000 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 } CustomInstancing { id: customInstancing instanceCount: 121 hasTransparency: true } Node { Model { id: transparentModel source: "#Cube" instancing: customInstancing materials: DefaultMaterial { diffuseColor: "lightgray" } } NumberAnimation on eulerRotation.y { from: 0 to: 360 duration: 30000 loops: -1 } } InstanceList { id: manualInstancing instances: [ InstanceListEntry { position: Qt.vector3d(0, 0, 0) color: "green" }, InstanceListEntry { position: Qt.vector3d(-300, 0, 200) color: "red" customData: Qt.vector4d(1.0, 0.0, 1.0, 1.0) }, InstanceListEntry { position: Qt.vector3d(200, 200, 100) color: "blue" customData: Qt.vector4d(0.0, 0.3, 1.0, 1.0) }, InstanceListEntry { position: Qt.vector3d(300, 0, 00) eulerRotation: Qt.vector3d(-10, 0, 30) color: "orange" customData: Qt.vector4d(0.0, 0.5, 1.0, 1.0) } ] } RandomInstancing { id: randomWithData instanceCount: 250 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) } NumberAnimation on instanceCountOverride { from: 1 to: randomWithData.instanceCount duration: 5000 } } 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 //instancing: manualInstancing materials: DefaultMaterial { diffuseColor: "white" } PropertyAnimation on eulerRotation.x { from: 0 to: 360 duration: 5000 loops: -1 } Model { id: sphereModel source: "#Sphere" instancing: parent.instancing instanceRoot: parent 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 Model { id: floor source: "#Rectangle" y: -500 scale: Qt.vector3d(15, 15, 1) eulerRotation.x: -90 materials: [ DefaultMaterial { diffuseColor: "pink" } ] } Repeater3D { model: cubeModel.instancing.instanceCount Model { id: delegate source: "#Cube" pickable: true property int instanceIndex: index position: cubeModel.instancing.instancePosition(index) scale: cubeModel.instancing.instanceScale(index) rotation: cubeModel.instancing.instanceRotation(index) property color instanceColor: cubeModel.instancing.instanceColor(index) visible: false } } } // View3D MouseArea { anchors.fill: viewport onClicked: (mouse) => { pickPosition.text = "(" + mouse.x + ", " + mouse.y + ")" var result = viewport.pick(mouse.x, mouse.y); if (result.objectHit) { var pickedObject = result.objectHit; pickName.text = "Index: " + pickedObject.instanceIndex pickColor.color = pickedObject.instanceColor 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) + ")"; worldNormal.text = "(" + result.sceneNormal.x.toFixed(2) + ", " + result.sceneNormal.y.toFixed(2) + ", " + result.sceneNormal.z.toFixed(2) + ")"; localNormal.text = "(" + result.normal.x.toFixed(2) + ", " + result.normal.y.toFixed(2) + ", " + result.normal.z.toFixed(2) + ")"; pickInfo.visible = true } else { pickInfo.visible = false pickName.text = "None"; uvPosition.text = ""; distance.text = ""; scenePosition.text = ""; localPosition.text = ""; worldNormal.text = ""; localNormal.text = ""; } } } Row { id: pickInfo visible: false anchors.left: parent.left anchors.bottom: parent.bottom anchors.leftMargin: 8 spacing: 10 Column { Label { color: "white" font.pointSize: 14 text: "Last Pick:" } Label { color: "white" font.pointSize: 14 text: "Instance color:" } Label { color: "white" font.pointSize: 14 text: "Screen Position:" } 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:" } Label { color: "white" font.pointSize: 14 text: "World Normal:" } Label { color: "white" font.pointSize: 14 text: "Local Normal:" } } Column { Label { id: pickName color: "white" font.pointSize: 14 } Rectangle { id: pickColor color: "transparent" width: pickName.width height: pickName.height } Label { id: pickPosition color: "white" font.pointSize: 14 } 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 } Label { id: worldNormal color: "white" font.pointSize: 14 } Label { id: localNormal color: "white" font.pointSize: 14 } } } DebugView { source: viewport anchors.top: parent.top anchors.left: parent.left TapHandler { onTapped: { if (cubeModel.instancing == randomWithData) { console.log("clicked: switching instance table to manualInstancing") cubeModel.instancing = manualInstancing } else if (cubeModel.instancing == manualInstancing) { console.log("clicked: switching instance table to fileInstancing") cubeModel.instancing = fileInstancing } else { console.log("clicked: switching instance table to randomWithData") cubeModel.instancing = randomWithData } } } TapHandler { acceptedButtons: Qt.RightButton onTapped: { customInstancing.depthSortingEnabled = !customInstancing.depthSortingEnabled console.log("right clicked: switching depth sorting to", customInstancing.depthSortingEnabled) } } } }