Qt Quick 3D Physics - Beispiel für zusammengesetzte Formen
Demonstriert die Verwendung komplexer Kollisionsformen.
Dieses Beispiel zeigt, wie man mehr als eine Kollisionsform verwenden kann, um komplexe Objekte für die Kollisionserkennung zu erstellen. Die Szene besteht aus einer grünen statischen Ebene und einer Reihe von miteinander verbundenen Verbindungen. Zu Beginn ist die Simulation deaktiviert. Nach einiger Zeit oder wenn der Benutzer die Leertaste drückt, wird die Simulation gestartet. Es wird eine Animation gestartet, bei der sich die Glieder ganz links und ganz rechts horizontal hin und her bewegen.
einrichten
Wie üblich müssen wir unsere PhysicsWorld hinzufügen:
PhysicsWorld { id: physicsWorld enableCCD: true maximumTimestep: 20 scene: viewport.scene }
Wir machen das übliche Setup, bei dem wir eine Umgebung, eine Kamera und Lichter haben:
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 shadowMapQuality: Light.ShadowMapQualityHigh }
Physische Objekte
Wir haben unsere normale statische Ebene:
StaticRigidBody { position: Qt.vector3d(0, -100, 0) eulerRotation: Qt.vector3d(-90, 0, 0) collisionShapes: PlaneShape {} Model { source: "#Rectangle" scale: Qt.vector3d(500, 500, 1) materials: DefaultMaterial { diffuseColor: "green" } castsShadows: false receivesShadows: true } }
Dann erstellen wir Instanzen unserer Links.
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" }
Die erste Verknüpfung auf der linken Seite hat die Eigenschaft isKinematic, die auf true
eingestellt ist, so dass wir sie per Animation steuern können. Da es sich um ein kinematisches Objekt handelt, müssen wir die Eigenschaften kinematicPosition und kinematicRotation einstellen. Wir animieren es, indem wir die Eigenschaft kinematicPosition animieren. Die anderen Links sind mit etwas Abstand zueinander instanziert.
Um eine flüssige Animation zu erhalten, die genau der physikalischen Simulation folgt, verwenden wir ein AnimationController, das wir mit dem onFrameDone
Signal auf dem PhysicsWorld verbinden. Auf diese Weise wird die Animation entsprechend verlangsamt, falls es zu Frame-Drops kommen sollte, die die Simulation verlangsamen. Wir verwenden ein SequentialAnimation mit vier NumberAnimation, um die Ringe ganz links und ganz rechts hin und her zu bewegen. Dies ist der QML-Code für die Animation:
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 } } }
Der interessante Teil ist, was in den Dateien Mesh und Capsule Links passiert. Werfen wir einen Blick auf jede einzelne Datei.
Mesh-Verknüpfung
DynamicRigidBody { scale: Qt.vector3d(100, 100, 100) property color color: "white" PrincipledMaterial { id: _material baseColor: color metalness: 1.0 roughness: 0.5 } Model { source: "meshes/ring.mesh" materials: [_material] } collisionShapes: [ ConvexMeshShape { source: "meshes/segmentedRing_001.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_002.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_003.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_004.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_005.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_006.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_007.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_008.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_009.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_010.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_011.mesh" }, ConvexMeshShape { source: "meshes/segmentedRing_012.mesh" } ] }
Der Mesh Link ist ein Dynamic Rigid Body mit einem Modell und einem Material. Das Modell lädt das Mesh aus einer Mesh-Datei. Wir haben auch eine Liste von Kollisionsformen, die zusammen kombiniert werden und eine zusammengesetzte Form für die Kollisionserkennung bilden. Jede Form ist eine konvexe Mesh-Form, die das Mesh aus einer Quelldatei lädt. Ein konvexes Shape ist im Grunde ein Shape, bei dem die Linie zwischen zwei beliebigen Punkten innerhalb des Shapes immer innerhalb des Shapes verläuft.
Wenn wir uns das genauer ansehen, wenn der Debug-Modus aktiviert ist, sehen wir, wie die Kollisionsformen die zusammengesetzte Kollisionsform bilden:
Capsule Link
DynamicRigidBody { property real len: 170 property real w: 17 PrincipledMaterial { id: material3 baseColor: "yellow" metalness: 1.0 roughness: 0.5 } Node { opacity: 1 Model { materials: material3 source: "#Cylinder" scale: Qt.vector3d(w / 100, len / 100, w / 100) eulerRotation.z: 90 y: -len / 2 } Model { materials: material3 source: "#Cylinder" scale: Qt.vector3d(w / 100, len / 100, w / 100) eulerRotation.z: 90 y: len / 2 } Model { materials: material3 source: "#Cylinder" scale: Qt.vector3d(w / 100, len / 100, w / 100) x: len / 2 } Model { materials: material3 source: "#Cylinder" scale: Qt.vector3d(w / 100, len / 100, w / 100) x: -len / 2 } Model { materials: material3 source: "#Sphere" scale: Qt.vector3d(w / 100, w / 100, w / 100) x: -len / 2 y: -len / 2 } Model { materials: material3 source: "#Sphere" scale: Qt.vector3d(w / 100, w / 100, w / 100) x: -len / 2 y: len / 2 } Model { materials: material3 source: "#Sphere" scale: Qt.vector3d(w / 100, w / 100, w / 100) x: len / 2 y: -len / 2 } Model { materials: material3 source: "#Sphere" scale: Qt.vector3d(w / 100, w / 100, w / 100) x: len / 2 y: len / 2 } } collisionShapes: [ CapsuleShape { y: -len / 2 height: len diameter: w }, CapsuleShape { y: len / 2 height: len diameter: w }, CapsuleShape { x: -len / 2 eulerRotation.z: 90 height: len diameter: w }, CapsuleShape { x: len / 2 eulerRotation.z: 90 height: len diameter: w } ] }
Das Capsule Link ist ein dynamischer Starrkörper mit einigen Modellen, die das gleiche Material verwenden. Diese Verbindung wird aus mehreren Zylindern und Kugeln gebildet. Wie beim Mesh Link haben wir eine Liste von Kollisionsformen. Diesmal ist jede Form eine Capsule Shape.
Wenn wir bei aktiviertem Debug-Modus einen genaueren Blick darauf werfen, sehen wir, wie die Kollisionsformen die zusammengesetzte Kollisionsform bilden.
Dateien:
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.