Qt Quick 3D 物理力学 - 质量示例

演示设置物体质量和惯性的不同方法。

本示例演示了设置物体质量和惯性的三种不同的方法。场景由三个竖直堆叠的球体组成,这些物体质量相同,但质量中心不同,惯性张量各异,因此在碰撞时表现出不同的行为。

设置

我们首先添加我们的 PhysicsWorld

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

我们进行通常的设置,包括环境、相机和灯光

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: 100
}

物理对象

我们有我们的常规静态平面

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

我们定义了一个用于我们物体的自定义 QML 类,我们称之为 RolyPoly,因为它们的行为类似于所谓的滚球玩具。RolyPoly 是一个带有三个球形碰撞形状的 DynamicRigidBody

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

然后,我们将三个 RolyPoly 添加到场景中

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
}

紫色和蓝色 RolyPoly 具有自定义的质量中心和中性张量。由于默认情况下,物体使用均匀密度并会自动计算质量,我们将质量模式设置为DynamicRigidBody.MassAndInertiaTensor,以便紫色和蓝色物体使用我们提供的质量和惯性张量。较低的质量中心将使物体在推动后会始终站立。紫色物体的惯性张量容易在一个方向上晃动,但很难在另一个方向上晃动。红色物体具有自动计算的质量中心,因此在被撞倒后会因此保持平躺。

射击球体

为了测试不同物体的行为,我们添加了一个用于射击球体的节点

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()
    }
}

然后,我们添加了一个 WasdController 来移动相机并瞄准射击球体

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

文件

© 2024 Qt 公司。其中包含的文档贡献属于各自的著作权人。本文件中的文档是根据自由软件基金会发布的GNU自由文档许可证版本1.3许可的。Qt及其相关标志是芬兰和/或其他国家/地区的Qt公司的商标。所有其他商标均为其各自所有者的财产。