[这个篇文章的主要目标是给予你一个关于在Unity中简单的优化物理系统]

  • 我的游戏物理系统有什么错误吗?
  • 怎么去处理游戏物理系统?
  • Unity 物理系统有什么缺陷吗?
  • Unity 是怎样处理物理系统的?
  • 我在 Unity 物理系统上做了什么控制?
  • 在我开始使用游戏物理系统之前我应该关心什么事情?
  • 我应该在时候避免使用物理系统?
  • 我看到了帧速率在下降,这是否是物理系统导致的?

 

当涉及到物理系统时,便会有以上这些问题,或许你会有更多像上面类似的问题。

 

是的,是的,我知道!我们全怪那个平果,它为什么要在那一天降临到牛顿的头上?为什么呢,上帝?

 

物理学也许不是每个人最爱的科目,但是物理学在游戏开发行业中真的是一个非常重要的角色。

 

想象一种情况,在紧要关头你最终决定提出做一个大事情。一个让人瞩目的,一个使用逼真的物理和图像的大游戏。

 

设计已经创建出来,架构已经完成,一切看上去似乎已经准备就绪。但是你最终坐了下来,开始在最棘手的部分上工作,“物理系统”!!

 

此时,似乎所以东西都崩溃了;你无意中看到了很低的FPS,奇怪的移动,碰撞器/触发器 出现了问题,高CPU使用率等等。

 

不恰当或者不正确的使用物理系统可能会把一些游戏玩家吓跑。这不只是关于不恰当的使用物理系统的问题了;这是关于一个游戏可玩性高不高的问题了。

 

这些都是不容易解决的问题。物理系统是游戏开发过程中最困难,也是最重要的一部份,这是无法避免的!!

 

人们可能会说:“好的物理系统需要一个超快的CPU!”。

 

但是,请相信我,这句话不一定都是对的。多数情况下,可以通过由浅入深进入Unity的海洋中学习Unity 的物理系统是怎样工作的,以便我们实现更好的物理系统。

 

在我还是一个程序小鲜肉的时候,我便要处理100多个与物理相关的事情。这让我花了近一年的时间记录下了处理物理相关的关键点。

 

因此,我决定写这篇文章。帮助大家跳跃这个学习阶段的痛苦,成为一个专业的物理系统开发者。

 

我不打算讲关于物理系统在Unity中是如何工作的,然而我将会在怎么优化你的物理系统中列出技巧和要点。所以,如果你是一个新手,我建议你先去大概了解一下Unity 物理系统。

 

物理学是一个非常非常庞大的、广泛的概念,我决定分成不同的部分,尽可能做到简单。

 

接下来,这是一个漫长有趣的过程,请你赶紧系好你的安全带,让我们开始吧!

 

降低固定时间步(Fixed Timestep)

在Unity文档的说明如下:

 

“一个不受帧速率影响的时间间隔,用于指定在 FixedUpdate() 函数中执行物理计算每一帧的时间间隔

 

默认值为 0.02(每秒),这显示了每 20ms(毫秒)物理更新将会被执行一次。所有 FixedUpdate() 也会每20ms调用一次。

 

你需要不停的改变这个值,以获得理想的效果。

 

例如:

 

“如果你打算做一个简单的卡牌游戏,这不需要使用太多的物理系统。然而最好减少调用物理引擎的次数。但是这操作要很细心一点;如果你减少过多的物理引擎调用的次数,你也许不会得到你想要的物理效果。”

 

让我们通过下面的案例更好的理解 Fixed Timestep 吧!

 

步骤 1) 创建 3-4 个 球体。让他们保持一些距离:

 

泰课在线

 

步骤 2)创建物理材质(通过在Assest文件夹中按下右键->Create->Phycics Material),并且设置摩擦系数(Friction Amount)的数值为 0 ,然后设置弹力系数(Bounciness)为 1,再设置弹力混合(Bounce combine)为最大值:

 

 

泰课在线

步骤 3)将该物理材质添加到球体碰撞器的物理材质卡槽中去:

 

泰课在线

 

步骤 4)为球体添加刚体组件(这将意味着此物体时物理对象):

 

泰课在线

 

步骤 5)创建一个平面,并且为其创建一个物理材质(先使用默认值),添加到平面上:

 

泰课在线

 

步骤 6)让创建的球体位于平面的上方,并且设置球体的重力选项盒为勾选状态。

 

泰课在线

 

步骤 7)点击 Play 按钮,并且查看一下结果。

 

这个球在做一下一上的动作。(不好意思,污了一下下。)

 

那么,这与固定时间步(Fixed Time Step)有什么关系呢?

 

上面只是一个简单的设置,现在我让我们开始玩耍 Fixed Time Step 的值吧!

 

找到 Edit>>Project Settings >> Time,在那里,你能找到 Fixed Time Step ,它的默认值为 0.02 (正如我之前提到的那样)。

 

泰课在线

 

现在让我们设置它为 0.1,然后按下 Play 按钮开始游戏。

 

你有发现有什么不同吗?

 

首先你会注意到,这些球的运动非常的慢。

 

然后,你会看到球体穿过了平面而不是反弹回来。

 

你会问为什么?(不需要弹跳如此的快呀!啊哈哈)

 

好的,如果你设置 Fixed Time Step 为 0.1,这就意味着物理更新将在每100ms(毫秒)执行一次,这很快就会注意到,将无法检测到碰撞。

 

这表明,过多的降低 Fixed Time Step 的也是不恰当的。现在让我们改变 Fixed Time Step

的值为一个更为实际可行的值 0.03 - 0.04。(具体根据球体的需要来定)

 

现在,如果你开始游戏,你不会看到任何改变。只要看上去还行,那就OK。如果你细心的检查一番,物理碰撞检测会有一点点不同的。

 

看看下面的图片:

泰课在线

 

提示

如果你不能跟上步骤来,那么请你参考一下Unity的官方文档。适当的理解 Unity 物理引擎是必须的。

物理碰撞检测会有点延迟,只会在当前帧结束之后才反弹回去。

 

这在你游戏处于正常FPS下可能观察不到,但是这可能会影响到物理效果。但只要你的需要满足了,这也是没什么关系的。

 

这将有什么帮助呢?

 

任何时候你从物理计算中节省下来的计算资源,都可以让给渲染和其他计算密集的处理,所以就可以让你的游戏更加出众。

 

通过设置 Maximum Allowed Timestep 在物理系统中保持检查!

 

Unity文档中的定义如下:

 

“一个不受帧速率影响的时间间隔,当帧率为最低峰值的时候,物理计算和 FixedUpdate() 事件将不会被执行”

 

那么,这意味着什么呢?

 

让我们先在正常的游戏下,去理解它(Maximum Allowed Timestep)。

 

如果你的游戏在运行的时候能保持在 60 FPS,这就意味着每一帧会执行 0.01666秒。意味着每一帧需要花费 16.7ms(毫秒)。

 

现在,让我们把 Fixed TimeStep 设置为 0.01,这表明物理更新将每 10ms 执行一次。

 

这表明,在每一帧中至少会调用一次物理更新,因为 10ms<16.7ms. 现在让我们假设由于某种原因帧率降低到了 30 FPS。

 

那么,每一帧将会执行 0.0333秒(也就是33.3ms) 。也就意味着在每一帧中会调用3次物理更新(因为一次物理更新花费10ms)。这意味着如果帧率继续下降,每帧内的物理调用还会更多。

 

这将会导致程序崩溃。为了解决这个问题,下面引入 Maximum Allowed TimeStep。

 

它的默认值为 33ms(可能是作者搞错了,明明就是0.33333秒 = 333。33ms啊)。正如 Maximum Allowed TimeStep 定义:每当物理更新超过指定的时间,物理更新将会停止。因此,这便为其他进程节约了资源。

 

在我们的案例中,如果每一帧执行时间增加到 40ms,这将会调用更多的物理更新。

 

但是现在我们设置 Maximum Allowed TimeStep 为 0.033,也就是33ms ,物理更新将会在 33ms 后停止调用,也就是执行3次物理更新后,便会停止调用,尽管每帧的执行时间超过 50ms 也会如此。

 

因此为其他沉重的进程节省下一些资源。

 

这听起来非常的棒,不是吗?

 

但还是有会一些限制的负面影响。每当发生性能故障,动画和物理便会放慢(意味着画面卡顿,延迟)。

 

因此,要牢记Maximum Allowed TimeStep 同样是一个重要的因素,如果使用得当,将会得到非常好的效果。

 

总是有 1-1-1 的比例

 

放大一个没有物理的对象是没有问题的(就是没有与物理相关组件的物体对象),但是当一个物体时一个物理对象时,我建议你不要对该物体进行缩放。缩放会导致奇怪的碰撞检测,也会影响到物体的下落方式。

 

例如:

 

“一块大石头在没有任何空气阻力的情况下会很快的落到地面上(如从塔上或其他地方掉下来)。但是如果它周围的物体都放大了,那会让下落看起来速度很慢”。

 

 

还有一个选项是调整重力加速度的值让他看起来变得正常,但是这不是最正确的做法。正确的做法应该是保持使用1-1-1的缩放比例,因为Unity的物理引擎在这种情况下工作的最佳。

 

给你的对象设置恰当的质量

 

和缩放一样,质量也需要保持精确。

 

让一架飞机的质量为 1kg 正确吗?

 

如果你考虑到度量系统准则,Unity的 1 个单位等于 1 kg 质量。同样的,Unity的 物理系统是无量纲的。但是,如果你假定 Unity 的一个单位的长度为米,那么,一个质量的单位为 kg。

 

你可以得到更完美的结果。并且,Unity在努力解决高浮点数问题,所以尽量削减取值范围是比较理想的解决方案。

 

这意味着,如果假设你的飞机重 1kg ,那么你的轮子必然不会超过 1/1000 kg。

 

尽可能避免使用网格碰撞器(Mesh Collider)

 

对任何物理引擎来说,基于网格的碰撞检测都比原始的碰撞检测需要更多的计算量,这是一个事实。Unity在内部使用了 Nvidia 的 PhysX,因此这是没有什么不同的。

 

一般来说,

 

“对于不同碰撞检测的相对成本从高到低的排序为:三角形网格、凸包(具体可以百度百科)、胶囊体、球体、盒子(六面体)、平面、点”

 

通常,网格碰撞器(Mesh Collider)被标记为凸包(也建议大家这么标记),它将被限制到255个三角形。只有在两个网格碰撞器被标记为凸面(Covex)时才能相互发生碰撞检测。

 

泰课在线

 

在 Unity 文档中的说明:

 

”使用网格碰撞器时会有一些限制。没有标记为凸面(Convex)的网格碰撞器只支持在一个没有刚体组件的游戏对象(GameObjecet)上发生碰撞,如果你想要在一个刚体上使用一个网格碰撞器,这必须要标记为凸面“

 

理想情况下,应该尽量避免使用网格碰撞体,因为他们会比传统的碰撞器(球体,立方体,胶囊体)带来更多的计算负载,所以最好还是少用。

 

替代