Auf dieser Seite

Qt Quick 3D Physik – Beispiel zur Masse

Veranschaulicht verschiedene Möglichkeiten, Masse und Trägheit eines Körpers festzulegen.

Screenshot einer 3D-Darstellung, die drei übereinander angeordnete Kugelformen auf einer grünen Fläche zeigt, die von links nach rechts blau, violett und rot gefärbt sind

Dieses Beispiel veranschaulicht drei verschiedene Möglichkeiten, die Masse und Trägheit eines Körpers festzulegen. Die Szene besteht aus drei Körpern, die sich aus drei vertikal übereinander angeordneten Kugeln zusammensetzen. Diese Körper haben alle die gleiche Masse, jedoch unterschiedliche Massenschwerpunkte und Trägheitstensor, wodurch sie sich bei einer Kollision unterschiedlich verhalten.

Einrichtung

Zunächst 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 übliche Einrichtung vor, bei der wir eine Umgebung, eine Kamera und Lichtquellen haben:

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 übliche statische Ebene:

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

Wir definieren eine benutzerdefinierte QML-Klasse für unseren Körper, die wir „RolyPoly“ nennen, da sie sich wie sogenannte Roly-Poly-Spielzeuge verhält. Das RolyPoly ist ein „ DynamicRigidBody “ mit drei kugelförmigen Kollisionsformen:

DynamicRigidBody {
    id: body
    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: body.color
        }
    }

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

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

Anschließend fügen wir unserer Szene drei Roly-Polys 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
}

Die violetten und blauen Roly-Polys verfügen über einen benutzerdefinierten Massenschwerpunkt und einen Trägheitstensor. Da Körper standardmäßig eine gleichmäßige Dichte verwenden und Masse sowie Trägheit automatisch berechnen, setzen wir bei unseren violetten und blauen Körpern `massMode` auf ` DynamicRigidBody.MassAndInertiaTensor`, um stattdessen unsere bereitgestellten Masse- und Trägheitstensoren zu verwenden. Durch den tiefer liegenden Schwerpunkt stehen die Körper immer wieder auf, nachdem sie umgestoßen wurden. Der Trägheitstensor des violetten Körpers sorgt dafür, dass er leicht in eine Richtung wackelt, in die andere jedoch kaum. Der rote Körper hat einen automatisch berechneten Schwerpunkt und bleibt daher liegen, nachdem er umgestoßen wurde.

Bälle abschieß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()
    }
}

Anschließend fügen wir einen „ WasdController “ hinzu, um die Kamera zu bewegen, zu zielen 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:

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