Auf dieser Seite

Qt Quick 3D Physik – Beispiel für zusammengesetzte Formen

Veranschaulicht die Verwendung komplexer Kollisionsformen.

Screenshot einer Landschaft mit mehreren quadratischen Rahmen und Ringen, die miteinander verkettet sind

Dieses Beispiel zeigt, wie man mehr als eine Kollisionsform verwendet, um komplexe Objekte für die Kollisionserkennung zu erstellen. Die Szene besteht aus einer grünen statischen Ebene und einer Reihe von miteinander verbundenen Verbindungsstücken. Zu Beginn ist die Simulation deaktiviert. Nach einiger Zeit oder wenn der Benutzer die Leertaste drückt, startet die Simulation. Es startet eine Animation, bei der sich die Gliederstangen ganz links und ganz rechts horizontal hin und her bewegen.

Einrichtung

Wie üblich müssen wir unsere „ PhysicsWorld “ hinzufügen:

PhysicsWorld {
    id: physicsWorld
    enableCCD: true
    maximumTimestep: 20
    scene: viewport.scene
}

Wir nehmen die übliche Einrichtung vor, bei der wir eine Umgebung, eine Kamera und Lichtquellen 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
}

Physikalische Objekte

Wir haben unsere übliche 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: PrincipledMaterial {
            baseColor: "green"
        }
        castsShadows: false
        receivesShadows: true
    }
}

Anschließend erstellen wir Instanzen unserer Verbindungen.

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"
}

Das erste Verbindungsglied auf der linken Seite hat die Eigenschaft „ isKinematic “ auf „ true “ gesetzt, damit wir es über eine Animation steuern können. Da es sich um ein kinematisches Objekt handelt, müssen wir die Eigenschaften „ kinematicPosition “ und „ kinematicRotation “ festlegen. Wir animieren es, indem wir die Eigenschaft „ kinematicPosition “ animieren. Die anderen Verbindungsglieder werden mit einem gewissen Abstand zueinander instanziiert.

Um eine flüssige Animation zu erhalten, die der physikalischen Simulation exakt folgt, verwenden wir einen „ AnimationController “, den wir mit dem Signal „ onFrameDone “ des „ PhysicsWorld “ verbinden. Auf diese Weise verlangsamt sich die Animation entsprechend, falls es zu Frame-Ausfällen kommen sollte, die die Simulation verlangsamen. Wir verwenden einen „ 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
        }
    }
}

Das Interessante daran ist, was in den Dateien „Mesh Link“ und „Capsule Link“ vor sich geht. Schauen wir uns jede davon einmal genauer an.

DynamicRigidBody {
    id: root
    scale: Qt.vector3d(100, 100, 100)
    property color color: "white"
    PrincipledMaterial {
        id: _material
        baseColor: root.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 dynamischer starrer Körper mit einem Modell und einem Material. Das Modell lädt das Mesh aus einer Mesh-Datei. Außerdem gibt es eine Liste von Kollisionsformen, die miteinander kombiniert werden und eine zusammengesetzte Form für die Kollisionserkennung bilden. Jede Form ist eine „Convex Mesh“-Form, die das Mesh aus einer Quelldatei lädt. Eine konvexe Form ist im Grunde eine Form, bei der die Verbindungslinie zwischen zwei beliebigen Punkten innerhalb der Form immer innerhalb der Form liegt.

Wenn wir uns das bei aktiviertem Debug-Modus genauer ansehen, bilden die Kollisionsformen wie folgt die zusammengesetzte Kollisionsform:

DynamicRigidBody {
    id: root
    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(root.w / 100, root.len / 100, root.w / 100)
            eulerRotation.z: 90
            y: -root.len / 2
        }
        Model {
            materials: material3
            source: "#Cylinder"
            scale: Qt.vector3d(root.w / 100, root.len / 100, root.w / 100)
            eulerRotation.z: 90
            y: root.len / 2
        }
        Model {
            materials: material3
            source: "#Cylinder"
            scale: Qt.vector3d(root.w / 100, root.len / 100, root.w / 100)
            x: root.len / 2
        }
        Model {
            materials: material3
            source: "#Cylinder"
            scale: Qt.vector3d(root.w / 100, root.len / 100, root.w / 100)
            x: -root.len / 2
        }
        Model {
            materials: material3
            source: "#Sphere"
            scale: Qt.vector3d(root.w / 100, root.w / 100, root.w / 100)
            x: -root.len / 2
            y: -root.len / 2
        }
        Model {
            materials: material3
            source: "#Sphere"
            scale: Qt.vector3d(root.w / 100, root.w / 100, root.w / 100)
            x: -root.len / 2
            y: root.len / 2
        }
        Model {
            materials: material3
            source: "#Sphere"
            scale: Qt.vector3d(root.w / 100, root.w / 100, root.w / 100)
            x: root.len / 2
            y: -root.len / 2
        }
        Model {
            materials: material3
            source: "#Sphere"
            scale: Qt.vector3d(root.w / 100, root.w / 100, root.w / 100)
            x: root.len / 2
            y: root.len / 2
        }
    }
    collisionShapes: [
        CapsuleShape {
            y: -root.len / 2
            height: root.len
            diameter: root.w
        },
        CapsuleShape {
            y: root.len / 2
            height: root.len
            diameter: root.w
        },
        CapsuleShape {
            x: -root.len / 2
            eulerRotation.z: 90
            height: root.len
            diameter: root.w
        },
        CapsuleShape {
            x: root.len / 2
            eulerRotation.z: 90
            height: root.len
            diameter: root.w
        }
    ]
}

Der „Capsule Link“ ist ein dynamischer starrer Körper, bei dem einige Modelle dasselbe Material verwenden. Diese Verbindung besteht aus mehreren Zylindern und Kugeln. Wie beim „Mesh Link“ gibt es auch hier eine Liste von Kollisionsformen. In diesem Fall handelt es sich bei jeder Form um eine Kapselform.

Wenn wir uns das bei aktiviertem Debug-Modus genauer ansehen, erkennen wir, wie die Kollisionsformen die zusammengesetzte Kollisionsform bilden.

Screenshot einer 3D-Darstellung, die zwei durch einen quadratischen Rahmen verbundene Ringe und deren starre Körper zeigt

Dateien:

© 2026 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.