首先附原文链接:https://unity3d.com/cn/learn/tutorials/topics/physics/physics-best-practices?playlist=30089
物理最佳实践
在本课中,我们将寻求一些在游戏中使用物理的最佳实践,以及一些证据来证明为什么要使用它们。
层和碰撞矩阵
所有的游戏对象(如果没有配置),都会被创建在默认层,在这个层默认所有的物体都会跟所有的物体碰撞。这是非常低效的。建立什么应该与什么相碰撞。为此,您应该给不同类型的游戏物体指定不同的层。每多一个新层,在碰撞矩阵上就会新增加一行和一列。这个矩阵负责定义层与层之间的交互。默认情况下,当增加一个新层的时候,碰撞矩阵会设置新层与其他存在的层都可以发生碰撞。所以开发者有责任访问它并建立其交互关系。通过正确的设置层与碰撞矩阵,您将避免碰撞监听器发生不必要的碰撞和测试。为了证明这个目的我制作了一个小的demo,我在盒子容器内生成了两千个物体(1000红色和1000绿色)。绿色的物体只和它们自己和容器壁交互,红色也一样。在其中一个测试中,所有的实例属于默认层,由碰撞监听器比对游戏对象的string类型的tag来进行交互。在另外一个测试中,每个物体的类型设置了其对应的层,我通过碰撞矩阵配置了每个层的交互。在这种情况下不需要字符串检测,因为只会发生正确的碰撞。
图1:碰撞矩阵配置(图片见原网页)
下面的图片取自demo,它有一个简单的管理器能统计碰撞的次数并在五秒后自动停止。当使用同一个层的时候不必要的多余的碰撞发生的次数非常可观。
图2:碰撞数量超过5秒(图片见原网页)
对于更具体的数据,我也在物理引擎上捕获了分析器数据。
图3:一个层vs分离层物理分析器数据(图片见原网页)
正如我们从分析器数据所见,使用一个层(平均〜27.7毫秒),分离层(平均〜17.6毫秒),CPU在物理上的花费相当不同。
射线
射线是物理引擎上一个非常有用且功能强大的工具。它允许我们在一个确定的方向上以一个确定的长度发射射线,它可以让我们知道射线是否触及某物。然而,这是一个昂贵的操作,它的性能受场景中射线的长度和碰撞体类型高度影响。
在使用它时这里有一些提示。
1.这一点非常明显,但是还是要说,使用最少量的射线来完成工作。
2.不要将射线的长度超过需要的长度。射线越长,需要检测的对象越多。
3.不要在FixedUpdate()函数内使用射线,有时甚至在Update()内部使用Raycasts可能会矫枉过正。
4.注意你正在使用的碰撞体的类型。对网状物碰撞器发射射线非常昂贵。
——一个好的解决方案是创建一个具有简单碰撞器的子物体,尝试贴近网格的形状。父刚体下所有的子碰撞体表现为一个复合碰撞体。
——如果迫切需要使用网格碰撞器,至少把它设置为convex(突出)。
5.具体说明射线应该击中什么,并尝试在射线函数中指定一个层蒙版。
——这在官方文档中有很好的解释,但是您在射线函数中指定的不是层ID,而是位掩码。
——所以如果你想要一个射线击中一个id为10的层上的对象,你应该指定的是1 << 10(比特移位“1”到左边10x)而不是10。
——如果你想让射线击中除了第10层以外的所有东西,那么只需使用按位取反运算符(〜)来反转位掩码上的每一位。
我开发了一个简单的demo,一个物体发射只与绿色盒子发生碰撞的射线。
图4:简单射线演示场景(图片见原网页)
在这里我修改射线的数量和长度来获取分析器数据,佐证我在上文写到的。我们可以从下面的图形中看到射线的长度和数量对性能的影响。
图5:射线数量对性能的影响(图片见原网页)
图6:射线长度对性能的影响(图片见原网页)
另外为了演示目的,我决定让它从简单碰撞器切换到网格碰撞器。
图7:网格碰撞器场景(每个碰撞器110个顶点)(图片见原网页)
图8:简单与网格碰撞体物理分析器数据(图片见原网页)
正如你从剖面图中看到的那样,对网格碰撞器进行射线投射使得物理引擎每帧的工作量更大。
物理2D与3D
选择什么物理引擎最适合您的项目,如果您正在开发2D游戏或2.5D(2D平面上的3D游戏),那么使用3D物理引擎是一种矫枉过正的行为,这个多余的维度会使您的项目发生不必要的CPU消耗。您可以查看我之前专门针对该主题撰写的文章中两种引擎之间的性能差异:http://x-team.com/2013/11/unity3d-v4-3-2d-vs-3d-physics/
刚体
在添加对象之间的物理交互时,Rigidbody组件是一个重要组件。即使使用碰撞器作为触发器,我们也需要将其添加到游戏对象中以使OnTrigger事件正常工作。没有RigidBody组件的游戏对象被认为是静态碰撞体。这一点很重要,因为尝试移动静态碰撞器效率极低,这会强制物理引擎再次强制计算整个物理世界。幸运的是,分析器将让你知道当你移动一个静态碰撞体的时候,会向CPU分析器的警报栏添加警告。为了更好地展示移动静态碰撞体时的影响,我移除了第一个demo中所有物体上的刚体,然后采集了分析器上新的数据。
图9:移动静态碰撞体警告(图见原网页)
从图中可以看到,总共产生了2000个警告,每个移动的游戏对象都有一个警告。同样,在物理上花费的CPU的平均时间从〜17.6ms增加到〜35.85ms,这是相当多的。移动游戏对象时,必须将RigidBody添加到游戏对象上。如果要直接控制其运动,只需给其勾选为刚体属性的运动学即可。
固定时间步
调整Time Manager上的Fixed Timestep值,这会直接影响FixedUpdate()和Physics更新速率。通过改变这个值,你可以尝试在精确度和CPU在物理上花费的时间之间达成很好的折衷。
总结
上述所有讨论的主题都很容易配置/实现,它们肯定会对您的项目性能产生影响,因为几乎所有您开发的游戏都将使用物理引擎,即使它仅用于碰撞检测。