Qt Quick 3D Physics - Beispiel Masse

Zeigt, wie Masse und Trägheit eines Körpers auf unterschiedliche Weise festgelegt werden können.

Dieses Beispiel demonstriert drei verschiedene Möglichkeiten, die Masse und Trägheit eines Körpers einzustellen. Die Szene besteht aus drei Körpern, die aus drei vertikal gestapelten Kugeln bestehen. Diese Körper haben alle die gleiche Masse, aber unterschiedliche Massenschwerpunkte und Trägheitstensoren, wodurch sie sich beim Zusammenstoß unterschiedlich verhalten.

Einrichtung

Zuerst fügen wir unsere PhysicsWorld hinzu:

PhysicsWorld {
    running: true
    gravity: Qt.vector3d(0, -9.81, 0)
    typicalLength: 1
    typicalSpeed: 10
    scene: viewport.scene
}

Wir nehmen die üblichen Einstellungen vor, d. h. wir haben eine Umgebung, eine Kamera und Lichter:

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

PerspectiveCamera {
    id: camera
    position: Qt.vector3d(0, 2, 5)
    eulerRotation: Qt.vector3d(-10, 0, 0)
    clipFar: 100
    clipNear: 0.01
}

DirectionalLight {
    eulerRotation.x: -45
    eulerRotation.y: 45
    castsShadow: true
    brightness: 1
    shadowFactor: 50
    shadowBias: 0.1
    pcfFactor: 0.01
}

Physikalische Objekte

Wir haben unsere normale statische Ebene:

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

Wir definieren eine benutzerdefinierte QML-Klasse für unseren Körper, den wir RolyPoly nennen, da er sich wie ein so genanntes RolyPoly-Spielzeug verhält. Das RolyPoly ist ein DynamicRigidBody mit drei kugelförmigen Kollisionsformen:

DynamicRigidBody {
    property string color: "blue"

    collisionShapes: [
        SphereShape {
            id: sphere0
            diameter:  1
        },
        SphereShape {
            id: sphere1
            diameter:  0.8
            position: Qt.vector3d(0, 0.6, 0)
        },
        SphereShape {
            id: sphere2
            diameter:  0.6
            position: Qt.vector3d(0, 1.1, 0)
        }
    ]

    Model {
        source: "#Sphere"
        position: sphere0.position
        scale: Qt.vector3d(1,1,1).times(sphere0.diameter*0.01)
        materials: PrincipledMaterial {
            baseColor: color
        }
    }

    Model {
        source: "#Sphere"
        position: sphere1.position
        scale: Qt.vector3d(1,1,1).times(sphere1.diameter*0.01)
        materials: PrincipledMaterial {
            baseColor: color
        }
    }

    Model {
        source: "#Sphere"
        position: sphere2.position
        scale: Qt.vector3d(1,1,1).times(sphere2.diameter*0.01)
        materials: PrincipledMaterial {
            baseColor: color
        }
    }
}

Wir fügen dann drei RolyPolys zu unserer Szene hinzu:

RolyPoly {
    position: Qt.vector3d(-2, 0.5, 0)
    color: "blue"

    mass: 0.9
    centerOfMassPosition: Qt.vector3d(0, -0.5, 0)
    inertiaTensor: Qt.vector3d(0.217011, 0.0735887, 0.217011)
    massMode: DynamicRigidBody.MassAndInertiaTensor
}

RolyPoly {
    position: Qt.vector3d(0, 0.5, 0)
    color: "purple"

    mass: 0.9
    centerOfMassPosition: Qt.vector3d(0, -0.5, 0)
    inertiaTensor: Qt.vector3d(0.05, 100, 100)
    massMode: DynamicRigidBody.MassAndInertiaTensor
}

RolyPoly {
    position: Qt.vector3d(2, 0.5, 0)
    color: "red"

    mass: 0.9
    massMode: DynamicRigidBody.Mass
}

Das lila und blaue RolyPoly hat einen eigenen Massenschwerpunkt und Trägheitstensor. Da Körper standardmäßig eine einheitliche Dichte verwenden und Masse und Trägheit automatisch berechnen, setzen wir massMode auf DynamicRigidBody.MassAndInertiaTensor in unseren lila und blauen Körpern, um stattdessen unsere bereitgestellten Masse- und Trägheitstensoren zu verwenden. Der niedrigere Massenschwerpunkt sorgt dafür, dass die Körper immer aufstehen, wenn sie umgestoßen werden. Der Trägheitstensor des lila Körpers sorgt dafür, dass er leicht in eine Richtung wackelt, aber kaum in die andere. Der rote Körper hat einen automatisch berechneten Massenschwerpunkt und bleibt daher nach dem Umstoßen liegen.

Bälle schießen

Um das Verhalten der verschiedenen Körper zu testen, fügen wir einen Knoten zum Schießen von Bällen hinzu:

Node {
    id: shapeSpawner
    property var spheres: []
    property var sphereComponent: Qt.createComponent("Sphere.qml")

    function createBall(position, forward) {
        let diameter = 0.2
        let speed = 20
        let sphere = sphereComponent.createObject(shapeSpawner, {
                                                      "position": position,
                                                      "sphereDiameter": diameter
                                                  })
        sphere.setLinearVelocity(forward.times(speed))

        var pair = {
            "sphere": sphere,
            "date": Date.now()
        }

        spheres.push(pair)

        if (sphere === null) {
            console.log("Error creating object")
        }
    }

    function clean() {
        spheres = spheres.filter(sphere => {
            let diff = Date.now() - sphere['date'];
            if (diff > 5000) {
                sphere['sphere'].destroy();
                return false;
            }
            return true;
        });
    }

    Timer {
        interval: 200
        running: true
        repeat: true
        onTriggered: shapeSpawner.clean()
    }
}

Wir fügen dann ein WasdController hinzu, um die Kamera zu bewegen und Bälle auf die Körper zu schießen:

WasdController {
    speed: 0.01
    shiftSpeed: 0.1
    controlledObject: camera
    Keys.onPressed: (event) => {
        handleKeyPress(event);
        if (event.key === Qt.Key_Space) {
            shapeSpawner.createBall(camera.position, camera.forward);
        }
    }
    Keys.onReleased: (event) => { handleKeyRelease(event) }
}

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.