Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

使用 Jolt Physics

介绍

Jolt 物理引擎作为现有 Godot Physics 物理引擎的替代方案于 4.4 版本加入。Jolt 由Jorrit Rouwe 开发,专注于游戏和 VR 应用。此前它仅作为扩展提供,现已内置于Godot。默认情况下,新项目将使用它作为物理引擎。

现有的扩展现在被视为处于维护模式。这意味着错误修复仍会被合并,并且它将保持与新版 Godot 的兼容性,直到内置模块的功能与扩展持平为止。目前唯一缺失的是相关的关节节点,你可以在本页面读到与其相关的内容。该扩展可以在 GitHub 以及 Godot 的资产库中找到。

要将 3D 物理引擎切换为 Jolt Physics,请将 项目设置 > 物理 > 3D > 物理引擎 设置为 Jolt Physics。完成此操作后,点击保存并重启按钮。当编辑器再次打开时,3D 场景将开始使用 Jolt 进行物理模拟。

与 Godot Physics 的主要区别

现有的 Godot Physics 引擎与 Jolt 之间存在诸多差异。

关节属性

目前 3D 关节节点的接口与 Jolt 自身关节的接口并不完全匹配。因此,有部分关节属性不受支持,主要是与配置关节软限制相关的属性。

不支持的属性有:

  • PinJoint3D:biasdampingimpulse_clamp

  • HingeJoint3D:biassoftnessrelaxation

  • SliderJoint3D:angular_**_limit/softness*_limit/restitution*_limit/damping

  • ConeTwistJoint3D:biasrelaxationsoftness

  • Generic6DOFJoint3D:*_limit_*/softness*_limit_*/restitution*_limit_*/damping*_limit_*/erp

当前若将这些属性设置为非默认值,会触发警告。

单物体关节

在 Godot 中,你可以为双体关节省略其中一个连接体,从而将“世界”作为另一个连接体。但是,你分配给关节的节点路径(node_anode_b)会被忽略。Godot Physics 总会表现得像你将其分配给了 node_a,而由于 node_a 也定义了关节限制的参考坐标系,这会导致限制条件被反转,并可能产生奇怪的限制形状——特别是当你的限制同时允许线性和角度自由度时。

Jolt 会表现得如同你将物体分配给了 node_bnode_a 则代表“世界”。如需兼容现有项目,可通过项目设置物理 > Jolt Physics 3D > 关节 > 世界节点切换此行为。

碰撞边距

Jolt(及其他类似物理引擎)采用了一种被 Jolt 称为“凸面半径”(convex radius)的技术,用于改善其依赖的凸形体之间的碰撞检测的性能和表现。其他物理引擎(包括 Godot)可能将其称为“碰撞边距”(collision margins)。Godot 在所有继承自 Shape3D 的类中都通过 margin 属性公开此参数,但 Godot Physics 引擎本身并未实际使用该属性。

在其他引擎中(如 Godot 文档所述),这些碰撞边距有时会为形状添加一个“外壳”,在略微增大形状尺寸的同时柔化边角。而在 Jolt 中,这些边距会先收缩原始形状,再应用“外壳”——这虽然同样会柔化边角,但不会改变形状的最终尺寸。

为避免手动调整边距属性(因其默认值可能导致较小形状出现问题),Jolt 模块提供了项目设置项:物理 > Jolt Physics 3D > 碰撞 > 碰撞边距分数。该值会与形状 AABB 的最小轴相乘来计算实际边距,而形状的 margin 属性则被用作上限值。

在大多数情况下,这些碰撞边距的影响微乎其微,但在进行形状查询时偶尔会导致异常的碰撞法线。你可以通过降低上述项目设置值(甚至设为 0.0)来缓解此问题,但边距过小同样可能引发异常碰撞结果,因此通常不建议这样做。

Baumgarte 稳定法

Baumgarte 稳定法是一种用于分离穿透物体并将其推至刚好接触状态的方法。在 Godot Physics 中,其工作原理类似弹簧。这意味着物体可能会加速,还可能导致物体过冲并完全分离。而 Jolt 仅对物体位置(而非速度)应用稳定,这意味着物体不会出现过冲,但可能需要更长时间来解决穿透。

可通过项目设置物理 > Jolt Physics 3D > 模拟 > Baumgarte 稳定系数 调整稳定强度。设为 0.0 将禁用该功能,设为 1.0 会单步完成穿透修正(速度最快但易失稳)。

幽灵碰撞

Jolt 采用两种技术缓解幽灵碰撞问题——即与形状/物体的内部边缘发生的碰撞,导致碰撞法线与运动方向相冲。

第一种技术称为“活动边缘检测”,它会根据与相邻三角形的夹角,将 ConcavePolygonShape3DHeightMapShape3D 中的三角形边缘标记为“活动”或“非活动”。当碰撞发生在非活动边缘时,碰撞法线会被替换为三角形面的法线,从而减轻幽灵碰撞的影响。

可通过项目设置物理 > Jolt Physics 3D > 碰撞 > 活动边缘阈值配置活动边缘检测的角度阈值。

第二种技术称为“增强内部边缘移除”,它会根据两个物体的接触点实时检测边缘是否活跃。该技术的优势在于不仅能处理与 ConcavePolygonShape3DHeightMapShape3D 的碰撞,还可消除同一物体内任意形状间的边缘碰撞问题。

可通过项目设置 物理 > Jolt Physics 3D > 模拟 > 使用增强内部边缘移除 及其对应的查询运动查询设置,分别控制是否在模拟、查询及运动查询中启用增强内部边缘移除功能。

请注意,活动边缘检测和增强内部边缘移除技术均不适用于处理不同物体间的幽灵碰撞情况。

内存占用

Jolt 在模拟步骤中使用栈分配器处理临时内存分配。该栈分配器需要预先分配固定大小的内存缓冲区,可通过项目设置 物理 > Jolt Physics 3D > 限制 > 临时内存缓冲区大小 配置缓冲区大小。

射线投射的面索引

使用 Jolt 时,intersect_ray() 和 RayCast3D 返回结果中的 face_index 属性默认始终为 -1。可通过项目设置物理 > Jolt Physics 3D > 查询 > 启用光线投射面索引 启用该功能。

启用此设置将导致 ConcavePolygonShape3D 的内存占用量增加约 25%。

运动学 RigidBody3D 接触

使用 Jolt 时,出于性能考虑,被 FREEZE_MODE_KINEMATIC 冻结的 RigidBody3D 默认不会报告与其他静态/运动学物体的碰撞接触,即使设置了非零的 max_contacts_reported。若存在大量/大型运动学物体与复杂静态几何体(如 ConcavePolygonShape3DHeightMapShape3D)重叠的情况,这可能会在不知不觉中浪费大量 CPU 性能和内存。

因此,该行为需要通过项目设置物理 > Jolt Physics 3D > 模拟 > 生成所有运动接触手动启用。

接触冲量

由于 Jolt 内部限制,PhysicsDirectBodyState3D.get_contact_impulse() 提供的接触冲量是预先根据接触流形和碰撞体速度估算得出的。这意味着仅当相关两个物体未与其他物体发生碰撞时,报告的冲量值才会准确。

Area3D 与 SoftBody3D

Jolt 支持与 Godot 物理引擎相同类型的 SoftBody3D (3D软体)和 Area3D (3D区域)之间的交互,例如 Area3D 上常见的风力和重力属性。不过,与 Godot 物理引擎不同的是,Jolt 还支持 Area3D 上的各种重叠信号和方法。也就是说,当 SoftBody3D 进入或离开某个区域的重叠范围时,Jolt 能够正常触发像 body_entered 这样的信号。

如果你想恢复到 Godot Physics(Godot 原生物理引擎)的行为模式,也就是不触发任何重叠(overlap)信号,你需要配置区域的 collision_mask ,确保它和软体(Soft Body)的 collision_layer 没有任何重叠。你也可以选择自己在信号连接中手动过滤掉任何 SoftBody3D 类。

WorldBoundaryShape3D

WorldBoundaryShape3D 用于表示无限平面,在 Jolt 中的实现方式与Godot Physics 略有不同。两个引擎都对该平面的有效尺寸设定了上限,但为避免精度问题,Jolt 中的尺寸上限要小得多。

可通过项目设置物理 > Jolt Physics 3D > 限制 > 世界边界形状尺寸配置此尺寸。

与 Godot Jolt 扩展的主要区别

内置 Jolt 模块虽基本沿用了 Godot Jolt 扩展的代码,但仍存在部分差异。

项目设置

所有项目设置已从 physics/jolt_3d 分类移至 physics/jolt_physics_3d

此外,部分项目设置也进行了重命名和重构,包括:

  • sleep/enabled 现已更名为 simulation/allow_sleep

  • sleep/velocity_threshold 现已更名为 simulation/sleep_velocity_threshold

  • sleep/time_threshold 现已更名为 simulation/sleep_time_threshold

  • collisions/use_shape_margins 现已更名为 collisions/collision_margin_fraction,其中值为 0 等同于禁用该功能。

  • collisions/use_enhanced_internal_edge_removal 现已更名为 simulation/use_enhanced_internal_edge_removal

  • collisions/areas_detect_static_bodies 现已更名为 simulation/areas_detect_static_bodies

  • collisions/report_all_kinematic_contacts 现已更名为 simulation/generate_all_kinematic_contacts

  • collisions/soft_body_point_margin 现已更名为 simulation/soft_body_point_radius

  • collisions/body_pair_cache_enabled 现已更名为 simulation/body_pair_contact_cache_enabled

  • collisions/body_pair_cache_distance_threshold 现已更名为 simulation/body_pair_contact_cache_distance_threshold

  • collisions/body_pair_cache_angle_threshold 现已更名为 simulation/body_pair_contact_cache_angle_threshold

  • continuous_cd/movement_threshold 现已更名为 simulation/continuous_cd_movement_threshold,且数值改用分数表示而非百分比。

  • continuous_cd/max_penetration 现已更名为 simulation/continuous_cd_max_penetration,且数值改用分数表示而非百分比。

  • kinematics/use_enhanced_internal_edge_removal 现已更名为 motion_queries/use_enhanced_internal_edge_removal

  • kinematics/recovery_iterations 现已更名为 motion_queries/recovery_iterations,且数值改用分数表示而非百分比。

  • kinematics/recovery_amount 现已更名为 motion_queries/recovery_amount

  • queries/use_legacy_ray_casting 已被移除。

  • solver/position_iterations 现已更名为 simulation/position_steps

  • solver/velocity_iterations 现已更名为 simulation/velocity_steps

  • solver/position_correction 现已更名为 simulation/baumgarte_stabilization_factor,且数值改用分数表示而非百分比。

  • solver/active_edge_threshold 现已更名为 collisions/active_edge_threshold

  • solver/bounce_velocity_threshold 现已更名为 simulation/bounce_velocity_threshold

  • solver/contact_speculative_distance 现已更名为 simulation/speculative_contact_distance

  • solver/contact_allowed_penetration 现已更名为 simulation/penetration_slop

  • limits/max_angular_velocity 现已改用弧度值存储。

  • limits/max_temporary_memory 现已更名为 limits/temporary_memory_buffer_size

关节节点

Godot Jolt 扩展中提供的关节节点(JoltPinJoint3D、JoltHingeJoint3D、JoltSliderJoint3D、JoltConeTwistJoint3D 和 JoltGeneric6DOFJoint3D)未包含在 Jolt 模块中。

线程安全

与 Godot Jolt 扩展不同,Jolt 模块具备线程安全特性,包括物理 > 3D > 在单独线程上运行项目设置的支持。但该功能尚未经过充分测试,应视为实验性功能。