Qt Quick 3D 物理引擎 - 复合形状示例
演示如何使用复杂碰撞形状。
该示例演示了如何使用多个碰撞形状来创建用于碰撞检测的复杂对象。场景由一个绿色静态平面和一系列相互连接的链接组成。一开始,模拟处于禁用状态。经过一段时间或用户按下空格键后,模拟将开始。将开始一个动画,使最左边和最右边的链接沿着水平方向来回移动。
设置
我们像往常一样需要添加我们的 PhysicsWorld
PhysicsWorld { id: physicsWorld enableCCD: true maximumTimestep: 20 scene: viewport.scene }
在具有环境、相机和灯光的常规设置中操作
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 shadowFactor: 15 shadowFilter: 10 shadowMapFar: 100 shadowBias: -0.01 shadowMapQuality: Light.ShadowMapQualityVeryHigh }
物理对象
我们有一个常规静态平面
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 } }
然后我们创建链接的实例。
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" }
最左侧的第一链接的 isKinematic 属性设置为 true
,这样我们就可以通过动画来控制它。由于它是运动学对象,我们需要设置 kinematicPosition 和 kinematicRotation 属性。我们通过动画它来动画化 kinematicPosition 属性。其他链接之间有一定的间隔。
为了获得平滑的动画,使其正好跟随物理模拟,我们使用一个AnimationController,它连接到 PhysicsWorld 的 onFrameDone
信号。这样,如果有帧丢失,导致模拟变慢,动画也会相应地减速。我们使用一个带有四个 NumberAnimation 的 SequentialAnimation 来移动最左边和最右边的环。这是动画的 QML 代码
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 } } }
有趣的部分在于 Mesh 和 Capsule Links 文件内部的情况。让我们分别看看每一个。
网格链接
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" } ] }
网格链接是具有模型和材料的动态刚体。模型从网格文件中加载网格。我们还有一个碰撞形状列表,这些形状组合在一起形成一个复合形状,用于碰撞检测。每个形状都是一个凸网格形状,它从源文件中加载网格。凸形状基本上是形状,其中形状内的任意两点之间的线总是在形状内部。
当开启调试模式并仔细观察时,我们可以看到碰撞形状是如何形成复合碰撞形状的。
胶囊链接
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 } ] }
胶囊链接是一种具有某些相同模型的动态刚体。这个链接由多个圆柱和球体组成。和网格链接一样,我们有一个碰撞形状列表。这次每个形状都是一个胶囊形状。
当开启调试模式并仔细观察时,我们可以看到碰撞形状是如何形成复合碰撞形状的。
文件
© 2024 Qt公司有限公司。本文件中包含的文档贡献物的版权属于其各自的所有者。本文件中的文档根据自由软件基金会发布的 GNU自由文档许可证版本1.3 的条款进行许可。Qt及其相关商标是芬兰及/或其他国家的Qt公司有限公司的商标。所有其他商标均属于其各自的所有者。