技术分享连载(五十二)

技术分享连载(五十二)

本期话题:动画模块性能优化、定位物理模块性能瓶颈、Static Batching合批规则...精选5个性能优化问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。
UWA QQ群:793972859


图形渲染

Q1:我们的游戏中有一些静止的建筑,会和整个场景一起烘焙(包括了每个建筑在地表的阴影)。现在希望这些建筑是逐步开放的,比如玩家1级的时候只有建筑A开放,2级的时候建筑B开放,现在的问题是当建筑未开放时(SetActive(false))地表的相关阴影还在。这种问题一般是怎么处理的?

这种问题是因为研发团队将整个场景烘焙成一张Lightmap所致。如果地图中的建筑是固定的,且游戏中并没有动态改变方向光的需求(比如Time Of Day模拟),那么可以尝试以下方法来实现需求:

(1)如果建筑物是根据等级而批量出现的,那么可以尝试根据等级不同而烘焙相应建筑群的Lightmap,然后在游戏中根据需求动态替换Lightmap;

(2)如果是逐个出现且建筑之间相距较为紧密的话,那么建议尝试通过Dynamic Projector(Asset Store插件)或Shadow Map(Unity自带阴影)来进行处理,因为Lightmap方法已无法支持这种需求。同时,可配合Fast Shadow Receiver(Asset Store 插件)来尽可能降低上述实时阴影带来的性能开销。


性能优化

Q2:在一个场景中有很多小物件,例如花花草草之类的静止物体,造成Draw Call数量较高。在不想让美术重新出资源的前提下,我是想把相同模型的东西合并,然后把小贴图打成一个大的贴图,重新算UV。还有比这种方法更好的优化手段吗?

对于场景中的静态物体,可直接尝试通过Unity的Static Batching方式来进行网格的合批,可以有效地降低由于Draw Call(5.x下的Batches)带来的性能开销。当然,Static Batching的前提是网格模型的材质相同,所以不仅需要保证Shader一致,还需要将各自的小纹理合成大纹理,从而保证Static Batching的顺利进行。

同时,如果渲染的网格面数较高,可以通过SimpleLOD、SimplyGon等常用网格简化工具对其进行快速减面。


动画

Q3:对于Animators.DirtySceneObjects这个参数,它是和哪些因素有关,以及如何优化?
请输入图片描述

该参数是更新场景中受Mecanim动画系统影响的每个GameObject的Transform,所以当这类的GameObject数量越多时,其CPU占用也会越高。对于它的优化方式,主要有如下两种:

  1. 如果是蒙皮网格物体,则可以开启“Optimize GameObject”选项来对其进行优化;
  2. 如果是非蒙皮网格(比如具有动画的UI界面、2D Sprite等),则只能建议研发团队尽可能减少同一时刻运动的GameObject数量(一般都不会太多),如果是被缓存的屏幕外的物体,则切记要在移出时关闭其Animator组件。

物理

Q4:请问Physics.Processing的占用过大一般是因为什么原因导致的?
请输入图片描述

影响物理系统耗时的因素主要为Contacts数量(碰撞对数量)、Rigidbody API的使用情况和每帧的调用次数。

  1. 第一种情况是最为常见的引发物理模块耗时较大的原因,因此,我们在UWA性能报告中对其进行了详细的分析,如果你的报告中Contacts数量较高,切记要验证其合理性。

  2. 第二情况造成较大CPU开销的情况不多,不过如果你的项目是多角色游戏(比如MMO、MOBA、ARPG割草游戏等),那么你需要注意了。在我们优化过的一些项目中,通过Rigidbody API来移动GameObject位置(设置velocity、改变center等)确实会存在较高的性能开销。如果你的项目也有类似的做法,那么要时刻关注物理模块的开销了。

  3. 第三种情况同样也是目前引发物理模块耗时较高的原因。因为Unity引擎默认情况下,物理的更新频率是0.02s,即每20ms更新一次,所以,当你的项目比较卡时(开发过程中的项目在中低端设备上恐怕没几个是不卡的),物理模块会让你的项目更卡。举个例子,如果上一帧CPU耗时为100ms的话,那么物理模块会执行5次,从而进一步加大物理系统的耗时。这种情况下,物理模块的耗时是很有欺骗性的,你花了好长时间去研究物理的耗时,最后发现原来这个“锅”不是它的...所以,如果你的项目也遇到了这种情况,切记不要再上当了。


性能优化

Q5:我游戏场景里有些草,勾选了Batching Static 如下图:
0.png
查看FrameDebug可以看到已经生成了Static Batch:
请输入图片描述
按道理来说这是的DrawCall应该是2,但是查看Profiler的时候却显示Draw Call为7,这是怎么回事呢?
请输入图片描述

从Unity 5.0开始,Static Batching的合批机制就已经出现了变化,不再进行索引数组的合批,因此并不会使得Draw Call降低,而是会降低Batches和SetPassCall,因此从图中来看,Static Batching 开启后的统计数据是没有问题的。也因此,UWA在统计时,使用的就是Batches的数值。具体的原因可见Unity官方在论坛中的回复:
https://forum.unity3d.com/threads/regression-feature-not-bug-static-dynamic-batching-combining-v-buffers-but-not-draw-calls.360143/

今天的分享就到这里。也欢迎热爱进步的你加入UWA的QQ群(793972859),也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。 比起闭门造车,我们更乐意与大家各抒己见,畅所欲言;比起形而上的泛泛而谈,我们更乐意与大家直击痛点,对症下药。