博毅创为Alan老师

导航

Unity性能调优技术集锦

性能调优,一直是游戏上线之前的很重要的一个环节, 游戏帧率过低,手机发烫, 低端机上跑不起来等, 这些都需要来做优化,今天我们来给大家分享Unity做性能调优的常用技术手段。

 

性能调优的指导思想

 

接触过很多刚做性能调优的小伙伴,他们做性能调优最大的问题就是缺乏一个做性能优化的指导思想, 导致很多想法做法,很片面,优化的效果也不好。要做性能调优,先来说说性能调优的指导思想。性能调优首先要分析问题,定位问题,证明是这块问题后再着色优化与想解决对策。

大家可以回想一下,多少次帧率低的时候,你的第一时间就是去查Drawcall, 去优化降低Drawcall,今天这个指导思想告诉我们,做性能优化之前,我们先定位,证明确实是Drawcall的问题导致性能下降。如何来定位问题,找出引起问题的代码和节点呢?这些给大家介绍一些方法。

 

(1)对比法

例如, 刚开始的时候帧率是60FPS,同一个场景运行一段时间以后是30FPS,如何优化,像这种符合很明显的对比场景,我们可以通过前后对比,来找出60FPS,30FPS,最大的变化。一般可以通过打开stats, 来观察前后主要的变化,main thread耗时,render thread耗时, 三角形面数,内存等信息,看看前后明显发生的变化。看到数据变化以后,再来思考整个过程中可能出现的问题,然后再证明, 再想优化对策。

 

(2)隔离法

这个是我经常用的一个方法, 就是隔离可疑区域和代码,然后比较,逐步排查,缩小问题范围。隔离法其实是非常好的方法,看上去很笨,很慢,但其实效率远比你想像的要好。比如,场景的物体过多,这个问题,那么我就可以采取隔离方法,先减少掉一倍,看效果。某个代码引发了帧率下降,可以逐步的注释掉代码,来观察结果,隔离的时候,可以采用二分查找,一半一半的排查。排查范围很快被缩小,问题也就精确的定位了。

 

(3)反经验法

上面介绍了常用的两种方法,定位问题,还有其他的一些方法,但是我想再说一个最重要的就是反经验法。你没看错,反经验,在性能优化的时候,不要相信经验,一步一步的逐步分析,有条不稳。不管什么问题,按部就班,不要根据经验,武断的下结论,要严格证明问题所在后再动手, 很多小伙伴遇到性能问题后,把问题简单的描述一下,去请教一个经验丰富的人,问他可能是哪方面的问题,我想说这种方式是很难做好你项目的性能优化的,项目和项目都不一样,连具体的问题都没有定位,你去请教经验丰富的老者,从老者的角度来说也无法帮到你。不要迷信经验,在动手前一定要定位好谁的问题,然后才能针对具体问题下对策。

 

优化从架构设计开始, 尽早验证核心玩法性能

好的框架设计,不仅让大家能很好的在一起工作,同时更方便我们快速的反应和定位问题。你的项目不好定位问题,那么一定是框架设计做的不好。所以开始做项目的时候,框架设计要花点时间,模块尽可能的独立,模块入口尽量清晰,整个框架设计能很好的隔离错误的蔓延。资源视图与逻辑代码分离,游戏数据与代码逻辑分离。这些都有助于快速的定位问题,比如我要验证是否物体过多,导致性能问题,只要在表格上配置一下,少放一些物体就可以验证,如果觉得是某个功能,倒是消耗CPU,可以把物体的这个功能的组件,关闭或不添加,比如怀疑怪物AI,可以注释掉添加怪物AI的组件。好的框架设计,定位问题的时候,就变得非常简单。如果是ECS框架,定位问题会更加接单,内存看Entity与资源,算法性能看System与物体规模……

接下来要给大家介绍的是我认为最重要的经验,就是尽早的验证核心玩法极限时候的性能开销与测试。不要等游戏项目做完了,才去验证,在设计初期验证完成后,一些性能问题会导致我们修改规格,修改玩法, 把这些问题越早摸清楚,是确保整个项目成功上线的关键。每个礼拜,建议把项目在不同的平台上测试,严格监测性能问题,哪个礼拜出现性能问题了,马上可以回溯复盘数据,着手摸清楚并解决。

 

Unity 性能优化方法集锦

1:包体体积优化:

声音文件优化: 将wav,压缩成mp3或ogg, 最好是ogg,没有版权问题, 将多声道变成单声道。改变声音的采样率与码率,减少声音文件体积。

贴图文件大小优化: 将png转jpg, 并使用图片压缩软件,压缩贴图体积, 尽量减少图片数目,复用图片,尽量能使用颜色等代码的方式来代替贴图。

3D模型文件: 根据需求适当降低模型面数, 去掉多余不用的数据, 可以通过法线贴图,高度贴图等降低模做出高模的效果, 合并贴图通道数据(PBR工作流中,将金属度,粗糙度,环境遮挡放一个纹理里面, 将数据合并到贴图不用的通道,比如Albedo贴图,Alpha通道不用,就可以存放环境遮挡等,节约贴图数目)

将资源ab包化: 把所有的资源分成一个一个的ab包,ab包本省有压缩功能,这样整体的包体也会减小,如果可能,可以把ab包全部放服务器,第一次运行游戏的时候再下载,比如《王者荣耀》,来节省包体体积。

 

2: 骨骼动画优化:

3D游戏中骨骼动画也是非常消耗性能的地方,因为每帧,我们都要通过动画组件采样,采样后重新计算出来我们的顶点的位置,传给GPU的渲染管线来处理, 我们可以将骨骼动画的每帧顶点的位置缓存到一个纹理贴图里面,用空间换时间的方式来节约动画组件的开销,并尝试合并Drawcall。

 

3: LOD的优化:

对于大规模多角色的场景游戏,我们要开启LOD,让远处的问题用尽量少的面,近处的物体用更多的面。

 

4: 模型细节增强,提升计算性能:

使用法线贴图,高度贴图等细节增强手段来降低模型的面数同时,能获得和高模同样的细节和更好的计算性能。

 

5: 光照优化:

静态光照烘焙+反射探头来做更好的场景效果,代替实时的光照计算,减少光源的数目。对于一些物体的发光特效,可以通过shader来实现,而不用加光源。定制Shader,可以将逐像素光照改为逐顶点光照,节约逐像素光照的计算开销。

 

6: SetPassCall与Drawcall优化

SetPassCall: 通俗的讲解就是更换重新装在渲染管线里面的Shader代码和配置,就像换画笔一样的。SetPassCall开销非常的大,所以尽可能的要少用一些不同的Shader,再一个场景里面。尽可能的让同一个Shader 绘制最多的物体后再切换下一个Shader。尽量避免绘制物体的时候平凡交叉的来回切换Shader来节约SetPassCall的次数。

Drawcall 优化,其实很简单三种优化手段,静态合批,动态合批,GPU Instancing合批, 然后我们针对合批的条件去达成对应的条件就可以了,比如,我们做一个捕鱼达人3D游戏,我们有很多的鱼,可以把鱼的所有纹理贴图,放到一个大图里面,这样,这些鱼就是同样的Shader,同样的纹理贴图对象,就可以达到合批的条件而做到合批, 节约Drawcall。

 

7: 物理引擎的优化:

能不用物理引擎的游戏,尽量不用物理引擎,能用代码自己实现的尽量用代码自己实现,因为物理引擎的开销毕竟摆在那里了, 用了代码很简单,但是性能开销也不可忽视。有一些不是真正的物理游戏,比如Moba类的游戏,防止物体穿透等,其实我们可以不用物理引擎,通过制作地图格子的方式,标记障碍物,自己控制的时候,如果进入障碍物的标记,就不让他更新即可,这些可以替换物理引擎获得很好的性能效果。常用的有菱形的地图格子与六边形的地图格子。

暂时不用的刚体,或者不在视线范围内的刚体可以根据游戏的需要,来显示和隐藏,达到节约物理引擎计算的目的。修改物理引擎全局的迭代参数,获得实用性的同时又有更好的性能。了解物理碰撞器的性能开销,球体最小,网格碰撞器最大,尽量使用开销小的碰撞器, 对于静态物体,能够合并物理碰撞器的尽量用一个物理碰撞器。

 

8: 阴影的优化:

通过开关控制阴影,在低端机上关闭阴影获得更好的运行帧率,在高端机上开启获得更好的运行效果。通过伪阴影技术来做贴图,节约阴影计算的开销, 可以自己定制Shader来实现高性能的阴影效果。

 

9: Shader优化:

减少Shader中的条件判断和展开循环,来获得更好的指令缓冲cache 命中率, 减少一些复杂的计算,可以采用一些空间换时间的方法来缓存计算结果。逐顶点计算来替代逐片元的计算,减少计算次数。可以把Shader 设置为常驻内存缓存,这样节约SetPassCall所带来的开销。

 

10: C#编写代码的习惯

Update里面尽量不要使用GetComponent, Find等,可以在初始化的时候先找出来,然后在Update里面使用, 能不放FixedUpdate尽量不放FixedUpdate, 这样低端机上能节约计算次数。

能降低FixedUpdate计算时间间隔的,尽量减少计算时间间隔,能减少计算的次数。写代码的平常的一些规范就不说了,避免大量的new 对象。一些重复使用的对象,可以通过节点池等原理先缓存起来。可以采用多线程来做一些计算避免卡住游戏线程导致帧率下降。不要再游戏住线程里面直接做同步的IO以免卡住游戏线程,导致帧率下降,从开始写代码起,要把每行代码写好,长期的坚持积累,才能形成良好的代码习惯写出高性能的代码,最重要的是学好数据结构与算法等基础知识,好的算法是好性能的关键。

 

还有很多的一些方面,我这边可能有遗漏的,大家可以留言讨论,后续如果有重要的我还会再更新。

posted on 2023-11-08 14:03  游戏开发阿博  阅读(47)  评论(0编辑  收藏  举报