查看原文
其他

教程:让Unity中物理效果更加逼真

2016-09-26 译者:崔嘉艺 Gad-腾讯游戏开发者平台

我的游戏物理部分有什么问题么?

该如何处理游戏的物理部分?

Unity的物理部分有什么问题么?

Unity是如何处理游戏的物理部分的?

我应该对Unity的物理部分做哪些控制?

在开始实现游戏的物理部分之前我应该注意什么事情么?

什么时候我该避免使用物理?

为什么我的游戏的帧数会下降?是由于物理部分的问题么?还是其他部分的问题?

当涉及到游戏的物理部分的时候,这个问题列表根本就没完没了,很明显,你可能有更多的这样的问题。

是的,是的,我知道!都怪那个苹果!为什么它要在那一天落下,而且要落在牛顿的头上?为什么?上帝,这是为什么?

物理可能不是每个人最喜欢的那个科目,但事实是,物理学在游戏行业的发展中起着非常重要的作用。

想象在这样一个情况下:你终于决定要做一些大事情!一些值得注意的事情!有很多现实物理和图形的大事情!这是一个大游戏,一切都岌岌可危!

设计已经完成了,架构也已经弄好了,看上去一切就绪。但是这时候你开始实现最有技巧的那个部分:”游戏的物理部分

一切都开始分崩离析,你遇到了低FPS、奇怪的运动、碰撞/触发方面的问题,CPU使用率很高以及其他各种各样的问题。

错误或不适当的物理表现可以赶走潜在的玩家。而且它涉及的不仅仅是物理表现的不正确,它还会让一个原本流畅的游戏体验变得延迟不舒服。

让物理部分表现的很恰当而且不影响效率是不容易达到的。的确,物理是游戏开发过程中最困难和最重要的一部分,而且你根本避不开,必须面对它!

人们可以争论说,好的物理表现需要非常快的CPU!”

但是相信我这并不总是真的!大多数时候可以通过深入分析Unity的原理来获得适当的物理表现!以及通过学习它是如何工作的来让物理部分表现的更好。

当我还是一个初学者的时候,我不得不处理100件和物理部分有关的事情。它大概花费了我一年的时间,我才记下在处理物理部分的时候需要记住的要点!

所以我决定写这篇文章,来帮你跳过这个痛苦的学习阶段,并成为游戏物理部分的专业开发人员!

我不会谈论如何使用Unity的物理部分,而我将列出技巧和要点来告诉你该如何优化你的游戏物理部分,所以如果你是一个初学者的话,我会建议你首先对Unity的物理部分有一个大概的了解。

因为物理是一个非常、非常、非常、非常(还可以有很多非常进行修饰:P)巨大而广泛的概念,我决定分成几个不同的部分和并尽可能的简化。

所以让我们开始吧!系好你的安全带,这将是一个漫长而愉快的旅程。


降低固定的更新时间间隔。。。!

Unity的文档是这么描述的,”物理部分的计算与更新是与帧速率无关的,FixedUpdate()时间也是与与帧速率无关的”。这个默认值是0.02(单位是秒),这意味着每20毫秒物理部分将要更新一次。所有的FixedUpdate() 函数也是20毫秒执行一次。

但是如果你的游戏不是严重依赖物理部分的话,你总是可以增加时间间隔,从而获得更好的结果。(即减少物理部分的调用)。

你需要对这个值进行测试调整来得到理想的效果。


让我们举个简单的例子:

如果你要做一个简单的纸牌游戏,没有太多使用物理的地方。最好是减少调用物理引擎的次数。但是需要记住这么一个事情:如果你把调用物理引擎的次数减少的太多的话,你可能不会得到恰当的物理表现。”


让我们通过下面这些例子来更好的理解这个事情

1在场景中摆放3- 4球。让他们彼此相隔一定距离。
2创建一个物理材料,并将摩擦系数减少为0,并将反弹系数设为1。
3将新创建的物理材质附加到球体的碰撞体物理材质上。
4给球体添加刚体组件(这将向引擎表明它是一个物理物体)。
5在场景中摆放一个平面,并且按需要来给这个平面添加物理材质。
6让球体保持在平面上的一定距离,并且让重力影响这些球体。
7按下播放键,检查结果。

这些球体会不停的弹上弹下。


这与固定时间步长有什么关系?

上面这些只是一些预设置,现在我们来调整下固定的时间步长值。

在菜单栏里面找到Edit >> Project Settings>> Time ,在这里你将看到Fixed Time Step Value:the value will be around 0.02(正如我之前提到的那样)。

现在把这个值提为0.1,然后再执行游戏。


你注意到区别是什么了么?

首先你会注意到球体有一些运动滞后。

其次,球体不会反弹了,而是直接穿过了平面。


为什么会这样?(不需要跳动的如此之快:P)

如果你把固定时间步长设置为0.1,那么这意味着物理部分的更新将每100毫秒发生一次,这很明显的有点过长了,并且将无法将测到碰撞。

这表明过多的降低固定时间步长也不是个很理想的情况。现在让我们改变时间步长为更实用的值0.03 - 0.04(根据你的球体的设置可能会有所不同)。

现在如果你执行游戏的话,你将无法看到任何变化。只要物理看起来适合你,那就没关系。如果你仔细检查的话,物理碰撞会略有不同。

看下下面这张图片:

请注意:
如果你不能按照这些步骤来一步一步的实现的话,请参考Unity的文档。因为对Unity物理部分有一个合适的理解是非常必要的。

你会注意到物理碰撞检测的有点晚,而且会在这一帧延迟一些才会反弹回去。

如果你的游戏能达到一个正常的帧率的话,可能这个效果并不明显,但它可能会对物理部分有影响。只要你的需求能够满足,那就没关系。


它将如何起作用?

从物理部分节省下来的处理时间将被渲染或者其他交互处理过程使用,因此你的游戏可以变得更加优秀!

通过设置所允许的最大时间步长来对物理部分的消耗做一个限制。。。!

正如Unity文档所描述的那样,

一个与帧速率无关的间隔时间指定了当帧率比较低的时候最坏的情况。物理部分的计算和FixedUpdate()事件的执行时间不会超过指定的这个间隔时间。"


所以这到底意味着什么?

为了理解这个事情,让我们首先来看下一个普通的游戏场景。

让我们假设下,你的游戏是以60fps的速度在运行,这就意味每一帧的执行时间是0.016666秒。也就是每帧所能花费的时间是16.7毫秒。

现在让我们假设固定时间步长(正如这篇文章中前面所讨论的那样)设置为0.01 ?这表明每10毫秒将执行一次物理更新。

这表明在每一帧,大约一次物理调用的时间大约在10毫秒到16.7毫秒之间。现在,让我们假设帧率已经由于某种原因下降到了30fps。

所以每一帧将花费0.0333毫秒。这也意味着在每一帧大概会有三次物理引擎的调用(因为每10毫秒将执行一次物理更新)。这也意味着如果帧率下降到30fps以下,每帧会调用更多次物理更新。

这简直是在杀死游戏。所以为了不出现这种情况引入了最大允许的时间步长。

它的默认值是0.3333秒或者是33毫秒。按照定义允许的最大时间步长,每当物理部分执行超过指定的时间,物理部分的执行将会停止,因此将给其他处理过程节省下时间。

如果在我们的例子中帧执行时间增加到40毫秒,它将会导致更多的物理调用。

但是现在我们已经设置了最大时间步长为0.333> > 33毫秒,所以33毫秒以后将不会再有物理调用,也就是这一帧的执行时间无论有多长,也不会有超过3次的物理部分的调用,哪怕这一帧的执行时间超过50毫秒。

因此这样可以为其他一些比较耗费计算资源的进程节省一些资源。

这听起来好得令人难以置信

但是这个限制还是有一些负面影响。一旦出现性能故障,那么物理和动画部分都会慢一些。

因此最大时间步长是一个非常重要的因素,需要紧紧牢记,如果使用恰当的话,结果将真的会非常引人注目。


总是具有1:1:1的比例

在没有物理部分的时候,缩放物体是没问题的,但是如果一个物体如果是作为物理对象对待的话,那么我会建议你不要对这个物体使用放缩。放缩会引起奇怪的碰撞,也会对物体时如何下落有影响。


让我们来举个简单的例子来说明下:

一个大石头,如果没有空气阻力的话,将落在地面上 (比如从塔之类的物体扔下来)。但如果假设周围的一切都相应的扩大的话,那么下降的速度会相当缓慢。”

总有一个选项是改变重力来让事物的表现正常起来,但这也不是正确要走的路。最简单的方法是控制放缩比例为1:1:1,因为Unity的物理部分最好是在这种情况下工作。

给你的物体设置合适的质量

就像大小一样,物体的质量也需要保持准确。


飞机的质量设为1千克是正确的么?

如果你考虑公制的,比如Unity1单位将等同于1千克的质量。因为Unity的物理系统是无量纲的。但是,如果你设定Unity的长度单位是米,那么它的质量的单位就该是千克。

你可以通过一些工作来得到完美的结果。同时,在Unity里面使用浮点数会有一些问题,所以如果可以的话,你最好可以尽可能地缩减其规模。

这意味着,如果假设你的飞机的重量是1千克的话,那么你的轮子的重量肯定不应该超过一千分之一千克。


尽可能地避免使用网格碰撞体

这是一个事实:基于三角形网格进行的碰撞检测计算相比较使用原始图元的碰撞体进行的碰撞检测计算在任何物理引擎都更耗费资源。Unity在内部也是使用的NvidiaPhysX物理引擎,所以这个结论对于Unity来说并没有什么不同。

一般来说,

不同类型进行碰撞检测的相对成本是按照以下顺序排序的,从最耗费资源到最不耗费资源:三角形网格、凸包、胶囊体、球体、立方体、平面、点”。

通常情况下,三角形网格的碰撞体会被标记为凸(而且这是建议的做法),因为这将限制碰撞体的大小不超过255个三角形。不同的三角形网格的碰撞体之间的碰撞只有在它们被标记为凸的情况下才会生效。

Unity的文档是这么说的,

 “在使用三角形网格的碰撞体的时候有一些限制。非凸的三角形网格的碰撞体只在没有刚体组件的游戏物体上是能够支持的。如果你想在一个刚体上使用三角形网格的碰撞体的话,它需要被标记为凸。”

理想情况下,使用三角形网格的碰撞体的使用需要尽可能的避免,因为基于三角形网格进行的碰撞检测计算需要大量的性能计算开销,比使用原始图元(球体、立方体、胶囊体)的碰撞体进行碰撞检测计算的消耗高得多,所以最好很少使用三角形网格的碰撞体。 


那有什么替代方案么。。。?

一个简单的替代方法是在物体的子物体里面聚合使用原始图元的碰撞体(如上面的图所展现的那样)。这样的话对于这个物体而言,可以导致较小的计算,因为使用原始图元的碰撞体意味着可以计算的更快。

对于复杂的网格的话,你总是可以使用Blender或是其他工具来将复杂的网格分成一些较小的网格。并在这些子网格上直接使用原始图元的碰撞体。

我希望我能给你一个确切的数字,告诉你通过优化到底节省了多少资源,但遗憾的是,因为不同的三角形网格差距比较大,得到一个确切的数字对我来说是非常困难的。


还有更多内容很快就会到来

这个列表很长,似乎根本就不会结束,让我们在这里休息一下,在下一篇文章里面继续讲解这些新技巧。

另外我也不希望因为讲了太多太多的物理方面的内容让你很不舒服:)。

当你开始使用上面提到的方法开始实践的时候,如果你找到一个更好的选择请与我们分享。如果你对上面的讨论有任何问题或者困惑的话,可以在文章下面的评论区留言,我很乐意提供帮助。

附注::“容易”这个词写在这篇文章的标题只是为了让你愿意阅读这篇文章,所以不要在乎这个单词。继续努力理解Unity的物理部分,最终你会明白它到底是如何工作的。:D

学习Unity看上去很有趣,是吧?为什么不看下我们其他的有关Unity的教程?

【版权声明】

原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。



点击一下立即阅读相关好文章


5个步骤制作完美3GCD丨聊一聊战斗维度与兵种设计丨


游戏美术3D设计干货回顾程序员跨界还可以做什么


这么做设计才好玩守望先锋为什么好玩


人民币玩家一样会被吊打


......


近期热文

Unix昔日之魂(一):设计模式的历史探索

Source引擎是如何处理多人模式下的模型同步?


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存