Qt Quick 3D Physics - Custom Shapes Example
// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick import QtQuick3D import QtQuick3D.Physics import QtQuick3D.Helpers import QtQuick.Controls import QtQuick.Layouts Window { width: 1280 height: 720 visible: true title: qsTr("QtQuick3DPhysics Custom Shapes") DynamicsWorld { id: physicsWorld running: true typicalLength: 2 enableCCD: true } View3D { id: viewport anchors.fill: parent environment: SceneEnvironment { clearColor: "white" backgroundMode: SceneEnvironment.SkyBox antialiasingMode: SceneEnvironment.MSAA antialiasingQuality: SceneEnvironment.High lightProbe: proceduralSky } Texture { id: proceduralSky textureData: ProceduralSkyTextureData { sunLongitude: -115 } } Texture { id: weaveNormal source: "maps/weave.png" scaleU: 200 scaleV: 200 generateMipmaps: true mipFilter: Texture.Linear } Texture { id: numberNormal source: "maps/numbers-normal.png" } Texture { id: numberFill source: "maps/numbers.png" generateMipmaps: true mipFilter: Texture.Linear } Node { id: scene scale: Qt.vector3d(2, 2, 2) PerspectiveCamera { id: camera position: Qt.vector3d(-45, 20, 60) eulerRotation: Qt.vector3d(-6, -13, 0) clipFar: 1000 clipNear: 0.1 } DirectionalLight { eulerRotation: Qt.vector3d(-45, 25, 0) castsShadow: true brightness: 1 shadowMapQuality: Light.ShadowMapQualityVeryHigh } StaticRigidBody { position: Qt.vector3d(-15, -8, 0) id: tablecloth Model { geometry: HeightFieldGeometry { id: tableclothGeometry extents: Qt.vector3d(150, 20, 150) heightMap: "maps/cloth-heightmap.png" smoothShading: false } materials: PrincipledMaterial { baseColor: "#447722" roughness: 0.8 normalMap: weaveNormal normalStrength: 0.7 } } collisionShapes: HeightFieldShape { id: hfShape extents: tableclothGeometry.extents heightMap: "maps/cloth-heightmap.png" } } DynamicRigidBody { id: diceCup isKinematic: true mass: 0 property vector3d restPos: Qt.vector3d(11, 6, 0) position: restPos pivot: Qt.vector3d(0, 6, 0) collisionShapes: TriangleMeshShape { id: cupShape meshSource: "meshes/simpleCup.mesh" } Model { source: "meshes/cup.mesh" materials: PrincipledMaterial { baseColor: "#cc9988" roughness: 0.3 metalness: 1 } } Behavior on eulerRotation.z { NumberAnimation { duration: 1500 } } Behavior on position { PropertyAnimation { duration: 1500 } } } StaticRigidBody { id: diceTower x: -4 Model { id: testModel source: "meshes/tower.mesh" materials: [ PrincipledMaterial { baseColor: "#ccccce" roughness: 0.3 }, PrincipledMaterial { id: glassMaterial baseColor: "#aaaacc" transmissionFactor: 0.95 thicknessFactor: 1 roughness: 0.05 } ] } collisionShapes: TriangleMeshShape { id: triShape meshSource: "meshes/tower.mesh" } } Component { id: diceComponent DynamicRigidBody { id: thisBody function randomInRange(min, max) { return Math.random() * (max - min) + min; } function restore() { reset(initialPosition, eulerRotation) } scale: Qt.vector3d(scaleFactor, scaleFactor, scaleFactor) eulerRotation: Qt.vector3d(randomInRange(0, 360), randomInRange(0, 360), randomInRange(0, 360)) property vector3d initialPosition: Qt.vector3d(11 + 1.5*Math.cos(index/(Math.PI/4)), 5 + index * 1.5, 0) position: initialPosition property real scaleFactor: randomInRange(0.8, 1.4) property color baseCol: Qt.hsla(randomInRange(0, 1), randomInRange(0.6, 1.0), randomInRange(0.4, 0.7), 1.0) collisionShapes: ConvexMeshShape { id: diceShape meshSource: Math.random() < 0.25 ? "meshes/icosahedron.mesh" : Math.random() < 0.5 ? "meshes/dodecahedron.mesh" : Math.random() < 0.75 ? "meshes/octahedron.mesh" : "meshes/tetrahedron.mesh" } Model { id: thisModel source: diceShape.meshSource materials: PrincipledMaterial { metalness: 1.0 roughness: randomInRange(0.2, 0.6) baseColor: baseCol emissiveMap: numberFill emissiveFactor: Qt.vector3d(1, 1, 1) normalMap: numberNormal normalStrength: 0.75 } } } } Repeater3D { id: dicePool model: 25 delegate: diceComponent function restore() { for (let i = 0; i < count; i++) { objectAt(i).restore() } } } SequentialAnimation { running: physicsWorld.running PauseAnimation { duration: 1500 } ScriptAction { script: diceCup.position = Qt.vector3d(4, 45, 0) } PauseAnimation { duration: 1500 } ScriptAction { script: { diceCup.eulerRotation.z = 130; diceCup.position = Qt.vector3d(0, 45, 0) } } PauseAnimation { duration: 3000 } ScriptAction { script: { diceCup.eulerRotation.z = 0; diceCup.position = Qt.vector3d(4, 45, 0) } } PauseAnimation { duration: 1500 } ScriptAction { script: diceCup.position = diceCup.restPos } PauseAnimation { duration: 2000 } ScriptAction { script: dicePool.restore() } loops: Animation.Infinite } } // scene } // View3D WasdController { keysEnabled: true controlledObject: camera speed: 0.2 } }