Qt Quick 3D Physics - Compound 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("Compound Shapes Example")

     PhysicsWorld {
         id: physicsWorld
         enableCCD: true
         maximumTimestep: 20
     }

     View3D {
         id: viewport
         property real ringY : 900
         property real ringDistance : 165
         anchors.fill: parent

         environment: SceneEnvironment {
             antialiasingMode: SceneEnvironment.MSAA
             backgroundMode: SceneEnvironment.Color
             clearColor: "lightblue"
         }

         focus: true

         PerspectiveCamera {
             id: camera
             position: Qt.vector3d(0, 900, 1500)
             eulerRotation: Qt.vector3d(-10, 0, 0)
             clipFar: 15500
             clipNear: 1
         }

         DirectionalLight {
             eulerRotation.x: -45
             eulerRotation.y: 45
             castsShadow: true
             brightness: 1.5
             shadowFactor: 15
             shadowFilter: 10
             shadowMapFar: 100
             shadowBias: -0.01
             shadowMapQuality: Light.ShadowMapQualityVeryHigh
         }

         StaticRigidBody {
             position: Qt.vector3d(0, -100, 0)
             eulerRotation: Qt.vector3d(-90, 0, 0)
             collisionShapes: PlaneShape {}
             Model {
                 source: "#Rectangle"
                 scale: Qt.vector3d(500, 500, 0)
                 materials: DefaultMaterial {
                     diffuseColor: "green"
                 }
                 castsShadows: false
                 receivesShadows: true
             }
         }

         MeshLink {
             id: leftLink
             isKinematic: true
             property vector3d startPos : Qt.vector3d(-6 * viewport.ringDistance, viewport.ringY, 0)
             property vector3d startRot : Qt.vector3d(90, 0, 0)
             kinematicPosition: startPos
             position: startPos
             kinematicEulerRotation: startRot
             eulerRotation: startRot
             color: "red"
         }

         CapsuleLink {
             position: Qt.vector3d(-5 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(90, 0, 0)
         }

         MeshLink {
             position: Qt.vector3d(-4 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(90, 0, 0)
         }

         MeshLink {
             position: Qt.vector3d(-3 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(0, 90, 0)
         }

         MeshLink {
             position: Qt.vector3d(-2 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(90, 0, 0)
         }

         MeshLink {
             position: Qt.vector3d(-1 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(0, 90, 0)
         }

         CapsuleLink {
             position: Qt.vector3d(0, viewport.ringY, 0)
         }

         MeshLink {
             position: Qt.vector3d(1 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(0, 90, 0)
         }

         MeshLink {
             position: Qt.vector3d(2 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(90, 0, 0)
         }

         MeshLink {
             position: Qt.vector3d(3 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(0, 90, 0)
         }

         MeshLink {
             position: Qt.vector3d(4 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(90, 0, 0)
         }

         CapsuleLink {
             position: Qt.vector3d(5 * viewport.ringDistance, viewport.ringY, 0)
             eulerRotation: Qt.vector3d(90, 0, 0)
         }

         MeshLink {
             id : rightLink
             isKinematic: true
             property vector3d startPos : Qt.vector3d(6 * viewport.ringDistance, viewport.ringY, 0)
             property vector3d startRot : Qt.vector3d(90, 0, 0)
             kinematicPosition: startPos
             position: startPos
             kinematicEulerRotation: startRot
             eulerRotation: startRot
             color: "red"
         }

         Connections {
             target: physicsWorld
             property real totalAnimationTime : 12000
             function onFrameDone(timeStep) {
                 let progressStep = timeStep/totalAnimationTime;
                 animationController.progress += progressStep;
                 if (animationController.progress >= 1) {
                     animationController.completeToEnd();
                     animationController.reload();
                     animationController.progress = 0;
                 }
             }
         }

         AnimationController {
             id: animationController
             animation: SequentialAnimation {
                 NumberAnimation {
                     target: leftLink
                     property: "kinematicPosition.x"
                     to: 3 * viewport.ringDistance
                     from: -6 * viewport.ringDistance
                     easing.type: Easing.InOutCubic
                     duration: 1000
                 }
                 NumberAnimation {
                     target: leftLink
                     property: "kinematicPosition.x"
                     from: 3 * viewport.ringDistance
                     to: -6 * viewport.ringDistance
                     easing.type: Easing.InOutCubic
                     duration: 1000
                 }
                 NumberAnimation {
                     target: rightLink
                     property: "kinematicPosition.x"
                     to: -3 * viewport.ringDistance
                     from: 6 * viewport.ringDistance
                     easing.type: Easing.InOutCubic
                     duration: 1000
                 }
                 NumberAnimation {
                     target: rightLink
                     property: "kinematicPosition.x"
                     from: -3  * viewport.ringDistance
                     to: 6 * viewport.ringDistance
                     easing.type: Easing.InOutCubic
                     duration: 1000
                 }
             }
         }
     }

     WasdController {
         controlledObject: camera
         speed: 0.02
         keysEnabled: true
         Keys.onPressed: (event)=> {
             if (keysEnabled) {handleKeyPress(event);}
             if (event.key === Qt.Key_Space) {
                 physicsWorld.running = true
             } else if (event.key === Qt.Key_G) {
                 physicsWorld.forceDebugDraw = !physicsWorld.forceDebugDraw
             }
         }
         Keys.onReleased: (event) => { if (keysEnabled) handleKeyRelease(event) }

     }
 }