前言
优化在游戏制作上是重中之重,良好的优化能给游戏带来更好的体验,同样也能压榨更多性能来实现更多的效果。对于个人开发者来说,早期规划优化内容方案与期望优化问题,对后期工作都有很大帮助。但是,许许多多的游戏并不是一个人就能完成的,线上线下团队合作,由于团队成员的习惯,或者是团队成员对某一方面的不自知,某一些不良设计就会导致项目卡顿。而优化这些内容,将会是必要的。我将会以我所遇到的所有可以优化内容作为整理,并且附上一些优化建议(如有遗漏或者不正确之处,欢迎指正)。
注意:以下参考为URP渲染管线,根据各自项目不同会有不同的优化内容,仅作优化方向的考虑和建议。
优化内容
1.CPU端
作为U3D技术美术发展方向,我实际上对主要的游戏核心逻辑并不参与,但是这并不代表我们不可以对其性能做分析。
使用Unity的Profiler工具可以作为我们分析性能的参考。
一般来说,第一个PlayerLoop(红框)是游戏声明周期的主要函数,像是我们自定义的C#脚本、游戏逻辑都会在这里执行,展开它找到消耗时间(Time)较多,或者是GC回调(GC Alloc)较多的函数,去定位哪一块出现了问题。然后找到其中主要消耗的原因。
在Unity生命周期中,Update是消耗的主要大头,所有能少在Update处理的逻辑就少用,可以采用协程这些手段,分摊到多帧进行处理。其次对于单帧来说,类似单帧生成许多物体(Instantiate)和销毁物体(Destory-GC回调)也会占用许多时间,采用对象池管理也是个很好的优化方向。
第二个PlayerLoop(绿框)是游戏渲染函数调用,大头一般是对摄像机数据初始化和数据的传输,减少游戏中摄像机的个数是很好的优化方向,其次减少摄像机的一些不必要功能的存在也是必要的。这一块同样可以展开树状图对其中的函数消耗进行相机定位分析。
2.渲染
2.1DrawCall优化
DrawCall(绘制调用)是指渲染引擎向图形硬件发送渲染命令,以渲染一个或者多个图形的过程,每一个DrawCall都代表一次绘制操作。减少绘制操作的频繁调用,是考虑减少CPU与GPU通信次数的手段。
Unity中存在四种合批手段,分别是SRPBatcher,GPUInstancing,动态合批与静态合批
其中详细解析:关于Unity四种合批技术详解_unity 合批-CSDN博客
采用合批手段,能很好的减少DrawCall次数,或者说是减少渲染批次,大大加快渲染的速度。
2.2UI合批
当你打开FrameDebugger时,发现UI渲染的批次竟然比主要内容还多时,你是不是会惊叹一下?UnityUI合批能很好的解决这些问题。打你需要了解Unity的精灵图集,并且合理分配和使用精灵图集的大小。
以下是详细的优化原理和操作:Unity3D UGUI系列之合批_unity ui合批-CSDN博客
2.3层级剔除
对于使用类似RenderTexture,额外相机渲染等,采用层级剔除,减少不必要的内容渲染
2.4粒子合批
Unity粒子系统合批的条件,就是使用相同的渲染材质,且需要相邻渲染。但是我们知道有时候粒子系统层级都是多个的,比如同一个粒子效果,有两份,正常来说它们应该合批,但是你打开FrameDebugger竟发现每一个粒子都是一个一个渲染的,并没有合批,这大大降低了渲染的速度。
制作粒子特效时,尽力用相同材质相同贴图的资源(贴图不同,可以进行图集合成变成相同的贴图),如果实在要穿插不同效果,那么设置粒子系统中Render模块的orderInLayer,保证相同特效在统一层级。
2.5相机设置
如果你的项目相机对天空球要求不多,就采用纯色模式。
对于后效,深度贴图,不透明贴图,阴影若是不需要则对它们进行关闭,HDRRendering或者是MSAA不需要也进行关闭。
在创建或者是使用相机功能时,只有唯一原则:“不需要则不使用,需要则再启用”。
2.6优化内置后处理,释放不必要RT
对于Unity内置的后处理系统,你可以找到PostProcessPass这个脚本对其进行优化处理,比如内置的Bloom。其次在程序动态生成RenderTexture时,在长时间不需要的情况下,将它们提前释放掉。
3.资源
3.1本地RenderTexture
在手动创建RT时,有很多都不会注意优化它们。设置好ColorFormat为低精度,如R8G8B8A8_UNORM已经足够应对大部分情况,关闭DepthFormat(如你不需要它,将会减少一半的RT资源大小),关闭抗锯齿提高分辨率,也许能更好的降低大小,视情况而定。
3.2优化Shader,汇编
减少Shader参数的精度,多采用乘法或者是加法,尽力避免动态分支的存在。减少采样的次数,这些小细节都会提高你Shader运算效率。多采用手写Shader,减少官方Shader或者是ShaderGraph的使用。
也许你不会注意Shader的运算方式,汇编代码能很好的帮助你了解Shader背后的代码。x*x+x会比x*(x+1.0)快上一些。
3.3场景资源
减少空节点的存在,尽管它只有一个Transform,但它仍会占用极少的空间。
如果你只存在一个场景,销毁当前进度长时间不需要的失活物体,尽管它们失活看不见了,但它们仍然占用资源。
3.4贴图
合理控制贴图的分辨率大小,mipmap生成次数,充分使用贴图的RGBA通道。