Unity物理系统由浅入深第二节:物理系统高级特性与优化

261 阅读10分钟

本次我们将简单讲解 Unity 物理系统的一些高级特性,例如物理层、各种关节、布料系统和车辆物理等,这些能够帮助我们理解复杂的物理模拟原理。同时,我们也会探讨物理系统的性能开销,并提供优化策略,确保我们的游戏在拥有丰富物理效果的同时,也能保持良好的帧率。


1. 物理层(Physics Layers):精细控制碰撞行为

在大型或复杂的场景中,你可能不希望所有物体都相互碰撞。例如,玩家的子弹应该能击中敌人,但不应该被场景中的装饰物阻挡。这时,**物理层(Physics Layers)**就派上用场了。通过合理设置层级,你可以精细控制哪些层之间可以发生碰撞,哪些不能。

设置步骤:

  1. 定义层: 在 Unity 编辑器中,选择一个 GameObject,在 Inspector 窗口的顶部点击 Layer 下拉菜单 -> Add Layer...。在这里你可以定义多达 32 个层(前 8 个是 Unity 内置的)。
  2. 分配层: 将你定义的层分配给场景中的 GameObject。
  3. 配置碰撞矩阵: 进入 Edit -> Project Settings -> Physics(对于 2D 物理是 Physics 2D)。在 Layer Collision Matrix 中,你会看到一个矩阵,它显示了所有层之间的碰撞关系。
    • 矩阵的行和列代表不同的物理层。
    • 当两个层对应的交叉点上的复选框被勾选时,这两个层之间的物体会相互碰撞。
    • 取消勾选,则这两个层之间的物体将忽略彼此的碰撞,从而节省物理计算资源。

应用场景:

  • 游戏逻辑分离: 将玩家、敌人、子弹、环境等分到不同的层,控制它们之间的交互。
  • 性能优化: 避免大量不必要的碰撞检测,例如背景中的小物体不需要与所有东西都碰撞。
  • 物理效果过滤: 某些特殊效果可能只希望与特定类型的物体互动。

2. 关节(Joints):连接与约束物体运动

Joints 组件允许你连接两个 Rigidbody,并对它们之间的相对运动施加约束。这对于创建铰链门、弹簧、角色布娃娃系统等非常有用。

Unity 提供了多种关节类型:

  • Fixed Joint (固定关节):将两个 Rigidbody 固定在一起,它们将像一个整体一样移动。
  • Hinge Joint (铰链关节):模拟门、铰链或车轮等旋转运动。你可以限制旋转角度,设置马达(motor)来驱动旋转,或者设置弹簧(spring)来让关节回到某个角度。
  • Spring Joint (弹簧关节):用弹簧连接两个 Rigidbody。你可以设置弹簧的强度(spring)、阻尼(damper)和断裂力(break force)。
  • Character Joint (角色关节):专门用于创建角色布娃娃(Ragdoll)系统。它模仿了人类关节的运动范围,可以限制每个轴上的摆动和扭曲。
  • Configurable Joint (可配置关节):这是最强大和灵活的关节类型。你可以自定义所有轴上的运动限制、弹簧、马达,以及相互连接的刚体如何关联(连接锚点、方向等)。如果你不确定使用哪种关节,或者需要非常特定的行为,Configurable Joint 通常是最终解决方案。

常用属性(以 Hinge Joint 为例):

  • Connected Body (连接刚体):指定要连接的另一个 Rigidbody。
  • Anchor (锚点):关节在本地空间中的连接点。
  • Axis (轴):关节的旋转轴。
  • Use Motor (使用马达):勾选后可以驱动关节旋转。
    • Target Velocity (目标速度):马达尝试达到的角速度。
    • Force Limit (力限制):马达施加的最大力。
  • Use Limits (使用限制):勾选后可以限制关节的旋转角度。
    • Min/Max Angle (最小/最大角度):关节可以旋转的范围。
  • Use Spring (使用弹簧):勾选后可以让关节像弹簧一样运动。
    • Spring (弹簧强度):弹簧将关节拉回原位的力。
    • Damper (阻尼):减缓弹簧振动的阻力。

布娃娃系统(Ragdoll)的构建: 布娃娃系统是 Character Joint 的一个典型应用。通过将角色的骨骼与 Character Joint 连接起来,当角色死亡或受到巨大冲击时,可以切换到布娃娃模式,让角色身体像真的一样瘫软倒地,增强真实感。


3. 布料系统(Cloth System):模拟柔软材质

Unity 的 Cloth 组件允许你模拟柔软、可变形的网格,例如旗帜、窗帘、角色的衣服或头发。它通过一系列粒子和弹簧来模拟布料的物理行为。

核心概念:

  • 粒子和约束: 布料网格的顶点被视为粒子,它们之间通过弹簧(约束)连接。
  • 外部力: 可以受到重力、风力等外部力的影响。
  • 与碰撞体的交互: 布料可以与场景中的 Collider 发生碰撞。

主要属性:

  • Damping (阻尼):减缓布料运动的阻力。
  • Stiffness (刚度):粒子之间连接的紧密程度,影响布料的“硬度”。
    • Stretching Stiffness (拉伸刚度):布料抵抗拉伸的强度。
    • Bending Stiffness (弯曲刚度):布料抵抗弯曲的强度。
  • Bending (弯曲):控制布料弯曲的程度。
  • External Acceleration (外部加速度):类似于重力,作用于所有布料粒子。
  • Self Collision (自碰撞):布料自身是否会发生碰撞。开启后更真实,但性能开销更高。
  • Constraints (约束):可以设置一些顶点固定或限制它们的运动范围。

使用场景: 飘动的旗帜、角色衣服的摆动、柔软的帐篷等。由于性能开销相对较高,通常用于对视觉效果要求较高且数量不多的物体。


4. 车辆物理(Wheel Collider):专业级的轮式载具模拟

Unity 提供了专门的 Wheel Collider 组件,用于模拟轮式载具的复杂物理行为,包括悬挂、摩擦力、转向和驱动。它比简单地使用通用 Rigidbody 和 Collider 组合能提供更真实的车辆体验。

核心概念:

  • 悬挂系统: 模拟车辆悬挂的压缩和伸展,吸收路面颠簸。
  • 轮胎摩擦模型: 更复杂的轮胎与路面之间的摩擦力计算,包括侧向(侧滑)和向前(驱动/刹车)的摩擦。
  • 理想化: Wheel Collider 是一个高度简化的模型,不模拟轮胎的真实形状或弹性,而是一个理想化的接触点。

主要属性:

  • Suspension (悬挂)
    • Spring (弹簧):悬挂的硬度。
    • Damper (阻尼):悬挂减震的程度。
    • Target Position (目标位置):悬挂的默认伸展长度。
  • Wheel Damping (车轮阻尼):减缓车轮旋转的阻力。
  • Force At (力点):施加力点的位置。
  • Mass (质量):车轮的质量(通常不需要设置,车辆总质量在 Rigidbody 上设置)。
  • Radius (半径):车轮的半径。
  • Motor Torque (马达扭矩):施加到车轮上的驱动力。
  • Brake Torque (刹车扭矩):施加到车轮上的刹车力。
  • Steer Angle (转向角度):车轮的转向角度。
  • Sideways Friction / Forward Friction (侧向摩擦 / 向前摩擦):定义轮胎的摩擦曲线,包括:
    • Extremum Slip (极限滑动):摩擦力达到最大值时的滑动量。
    • Extremum Value (极限值):最大摩擦力值。
    • Asymptote Slip (渐近滑动):摩擦力开始趋于平稳时的滑动量。
    • Asymptote Value (渐近值):摩擦力最终稳定的值。

使用步骤:

  1. 为车辆的根对象添加 Rigidbody。
  2. 为每个车轮(通常是子对象)添加 Wheel Collider。
  3. 通过脚本控制 Wheel Collider 的 motorTorquebrakeTorquesteerAngle 属性来实现车辆的驱动、刹车和转向。

5. 物理调试器(Physics Debugger):可视化与问题诊断

当物理行为出现异常时,Physics Debugger 是你最好的朋友。它允许你在编辑器中可视化物理碰撞体、射线检测、睡眠状态等信息,帮助你快速定位问题。

开启方式:

在 Unity 编辑器中,点击 Window -> Analysis -> Physics Debugger

主要功能:

  • Colliders (碰撞体):显示所有碰撞体的轮廓。可以按类型、是否触发器等筛选。
  • Contacts (接触点):显示碰撞发生时的接触点和法线。
  • Sleep (睡眠状态):显示 Rigidbody 是否处于睡眠状态(当物体长时间静止时,物理引擎会将其设为睡眠,停止计算,节省性能)。
  • Constraints (约束):显示关节的连接和限制。
  • Raycasts / Overlaps (射线/重叠检测):如果你的脚本中有 Raycast 或 OverlapSphere 等 API 调用,可以在这里看到它们的实时检测情况。

使用场景: 调试穿透问题、碰撞不准确、关节行为异常、物理性能瓶颈等。


6. 物理系统性能优化:让模拟更流畅

物理计算是 CPU 密集型操作,尤其是在有大量 Rigidbody 或复杂碰撞体的场景中。优化物理性能对于保持游戏流畅至关重要。

优化策略:

  1. 减少 Rigidbody 数量: 只有需要受到物理力影响的物体才添加 Rigidbody。对于静态或不需要物理交互的物体,只保留 Collider 或不使用物理组件。
  2. 简化 Collider 形状: 优先使用 Box、Sphere、Capsule 等原始碰撞体。尽量避免或减少使用非凸(non-convex)的 Mesh Collider。如果必须使用 Mesh Collider,请确保勾选 Convex 选项。
  3. 合理设置物理层: 通过 Layer Collision Matrix 禁用不必要的层间碰撞,可以显著减少碰撞检测的计算量。
  4. 调整 Fixed Timestep
    • 进入 Edit -> Project Settings -> Time
    • Fixed Timestep 是物理引擎更新的频率。默认是 0.02 秒(每秒 50 次更新)。
    • 减小 Fixed Timestep 会增加物理模拟的精确度和稳定性,但会增加 CPU 开销。
    • 增大 Fixed Timestep 会降低精确度,可能导致高速物体穿透,但能提高性能。
    • 根据游戏类型和需求进行权衡。对于精确物理模拟(如赛车游戏),可能需要较小的 Fixed Timestep;对于休闲游戏,可以适当增大。
  5. 合理使用 Collision Detection 模式:
    • 大多数 Rigidbody 使用 Discrete 模式。
    • 只有高速移动且可能穿透的 Rigidbody 才考虑使用 ContinuousContinuous Dynamic
    • 不要在所有 Rigidbody 上都使用 Continuous Dynamic,因为它的性能开销最高。
  6. 利用睡眠状态 (Sleeping):
    • 当 Rigidbody 静止一段时间后,物理引擎会将其设为“睡眠”状态,停止对其进行计算,直到有外力施加或与其发生碰撞。这是自动的,但你可以通过 Rigidbody.Sleep()Rigidbody.WakeUp() 手动控制。
    • 确保你的场景中没有不必要的“抖动”物体,它们会阻止 Rigidbody 进入睡眠状态。
  7. 避免在 UpdateLateUpdate 中直接操作 Rigidbody 的 transform
    • 直接修改 transform.positiontransform.rotation 会覆盖物理引擎的计算,可能导致不稳定的物理行为和性能问题。
    • 应该通过 Rigidbody.MovePosition()Rigidbody.MoveRotation() 或施加力/冲量的方式来控制 Rigidbody 的运动。
    • 物理相关的代码应放在 FixedUpdate 中执行。
  8. 减少布料和复杂关节的数量: 这些组件的计算成本较高,只在必要时使用。
  9. 烘焙 NavMesh 或 Occlusion Culling: 虽然不是直接的物理优化,但它们可以减少场景中的活动对象数量,从而间接减少物理交互的复杂性。

总结

现在我们已经了解了 Unity 物理系统的更多高级功能,并了解了如何对其进行优化。从精细的碰撞层控制,到复杂的关节和布料模拟,再到车辆物理的实现,这些都为我们的游戏增加了更多的可能性。更重要的是,我们现在知道如何通过调整各种参数和遵循最佳实践来确保物理模拟既真实又高效。

下一篇,我们将开始深入探索物理引擎的底层原理,揭开它内部工作的神秘面纱。