Unity最佳实践-物理最佳实践

Best Practices(1) - Physics Best Practices

本文翻译自Unity官方教程中的最佳实践教材,里面包含了很多原理分析,现在网上关系Unity的知识,水平参差不齐,很多都是不准确的,所以尝试翻译一些Unity官方的资料
原文地址:https://unity3d.com/cn/learn/tutorials/topics/physics/physics-best-practices?playlist=30089

  • 在本章中,我们将聚焦在一些如何在游戏中使用物理效果以及为啥应该被这样使用的最佳实践

Layers和Collision Matrix

所有的游戏对象,在创建的时候都会被设置为Default层级,这个层级默认的会和任意层级发生碰撞,这意味着性能是非常低效的,当然,可以通过为每种对象设置不同的层级来建立它们的碰撞关系。每个新的层级,都会在Collision Matrix中增加一个新的行和列,这个矩阵主要是负责定义层与层的互动关系。默认的,当你添加了一个新的层级后,Collision Matrix中会被设置为可以和任意层级互动,包括自己,所以,这也是开发者的责任去设置这个层级的互动关系。通过正确的设置层级和Collision Matrix,你会避免不需要的碰撞,还有不需要的碰撞监听测试。出于测试目的,我创建了一个简单的demo,在demo中我会实例化2000个对象(1000个红色的,1000个绿色的)在一个立方体容器中。绿色对象仅仅和自己以及容器会发生互动关系,红色的对象也是一样的规则。在一个测试中,所有的对象都设置为Default层级,他们的互动是通过字符串比较碰撞监听器上的游戏对象标签(tag)完成的。另一个测试中,每个类型的对象会被设置为他们自己的层级,然后我通过Collision Matrix设置每个层级的互动关系。在这个例子中,就不需要字符串对比就有正确的碰撞发生
Unity最佳实践-物理最佳实践
下面的图片取自demo。 它有一个简单的管理器来计算碰撞量并在5秒后自动暂停。 使用default图层时发生的不必要的额外冲突的数量相当可观。
Unity最佳实践-物理最佳实践
更具体的数据可以查看下面在profiler中physics engine的截图
Unity最佳实践-物理最佳实践
可以看出CPU花在物理部分的耗时差别是很大的,正如我们从profiler中看到的数据,使用同一个层级(平均27.7ms)到分离不同的层级(平均17.6ms)。

射线

射线是一个非常有用和强大的工具,建立在物理引擎上。它允许我们去发射一个射线,从一个确定的方向,确定的长度,然后你可以知道它碰撞到了什么东西。当然,这也是一项性能开销很大的操作,它的性能很受射线的长度和场景中的collider的类型影响。

这里有几个可以帮组它的使用的提示。

  • 第一个很明显,尽量使用最少的射线数量来完成工作
  • 控制射线长度在你需求的范围内。射线越长,需要测试的物体越多
  • 不要在FixedUpdate中使用射线,有时候,即使在Update中也可能过度使用了(sometimes even inside an Update() may be an overkill)
  • 注意colliders的类型,用射线检测mesh collider真的很耗时
    • 一个解决方法是创建一个子节点,使用形状相似的mesh作为collider。在一个父节点Rigibody下的所有collider都被当做一个复合的collider
    • 如果你真的需要使用mesh colliders,至少使用一个凸边形的网格
  • 要确定射线具体要碰撞什么,并且要养成在Raycast中使用图层mask的习惯
    • 在Unity的官方文档有关于这个方法的详细说明,需要提醒的是,在Raycast方法中使用的不是layer,而是layer的掩码
    • 所以如果你想让射线碰撞一个layer id为10的物体,你应该使用1<<10,而不是10
    • 如果是除了layer id为10的物体,其他的都碰撞,应该使用反转运算符(~)、
      这里有一个小的demo,一个物体发射射线,之和绿色物体发生碰撞
      Unity最佳实践-物理最佳实践
      在这里面,我通过控制射线的数量和长度,以获得一些profiler数据来验证上面的内容,我们可以从下图的图表中看到光线数量和光线长度对性能的影响
      Unity最佳实践-物理最佳实践
      Unity最佳实践-物理最佳实践

同样出于测试的目的,我把一些原生的collider改成mesh collider
Unity最佳实践-物理最佳实践
Unity最佳实践-物理最佳实践
你可以从上面看出,用射线检测mesh collider会让物理引擎在每帧做更多的工作

Physics 2D vs 3D

选择对你项目最好的物理引擎。如果你开发的是2D游戏或者2.5D(就是3D游戏,以2D的方式展示),使用3D物理引擎就有点浪费了。额外的维度会给你的工程带来不必要的CPU消耗。您可以查看我之前专门针对该主题撰写的文章中两种引擎之间的性能差异:
http://x-team.com/2013/11/unity3d-v4-3-2d-vs-3d-physics/

Rigidbody

当给物体添加物理交互时,刚体组件是一个重要的组件。即使是把colliders作为触发器使用,我们也需要加上这个组件,以保证OnTrigger正常工作。没有刚体组件的游戏对象会被当做是静态的collider。这一点很重要,因为移动静态碰撞器的效率非常低,它会让物理引擎强制重新计算物理世界。不过幸运的是,profiler上面的警告标签会添加警告,来通知你是否正在移动静态碰撞器。为了更好的展示移动静态碰撞器的影响,我删除了第一个演示中所有移动对象的Rigidbody,下面是profiler的数据
Unity最佳实践-物理最佳实践

Fixed Timestep

调整Time Manager上的Fixed Timestep值,这会直接影响FixedUpdate()和Physics更新速率。 通过改变这个值,你可以尝试在精确度和CPU时间之间达成很好的折衷。

总结

所有讨论的主题都很容易配置/实现,它们肯定会对您的项目性能产生影响,因为几乎所有开发的游戏都将使用物理引擎,即使它仅用于碰撞检测。