这个专栏我们会阐述一些unity中常见的优化技术,这些技术基本都是和渲染相关的,例如使用批处理、LOD(Level of Detail)技术等。
游戏优化不仅是程序员的工作,更需要美工人员在游戏的美术上进行一定的权衡,例如避免使用全屏的屏幕特效,避免使用计算复杂的shader,减少透明混合造成的overdraw等。这是由程序和美工人员等各部分人员共同参与的工作。
一、移动平台的特点
和PC平台相比,移动平台的GPU架构有很大的不同。由于处理资源等条件的限制,移动设备上的GPU架构专注于尽可能使用更小的带宽和功能,也由此带来了许多和PC平台完全不同的现象。
例如为了尽可能移除那些隐藏的表面,减少overdraw(即一个像素被绘制多次),PowerVR芯片(通常用于IOS设备和某些Android设备)使用了基于瓦片的延迟渲染(TBDR)架构,把所有的渲染图像装入一个个瓦片中,再由硬件找到可见的片元,而只有这些可见片元才会执行片元着色器。另一些基于瓦片的GPU架构,如Adreno(高通的芯片)和Mati(ARM的芯片)则会使用Early-Z或相似的技术进行一个低精度的深度检测,来剔除那些不需要渲染的片元。还有一些GPU,如Tegra(英伟达的芯片),则使用了传统的架构设计,因此在这些设备上,overdraw更可能造成性能的瓶颈。
由于这些芯片架构造成的不同,一些游戏往往需要针对不同的芯片发布不同的版本,以便对每个芯片进行更有针对性的优化。尤其是在Android平台上,不同设备使用的硬件,如图形芯片、屏幕分辨率等,大相径庭,这些对图形优化提出了更高的挑战,IOS平台硬件条件则相对统一。
二、影响性能的因素
首先学习如何优化之前,我们得了解影响游戏性能的因素有哪些。对于一个游戏来说,它主要使用两种计算资源:CPU和GPU。它们会互相合作,来让我们的游戏可以在预期的帧率和分辨率下工作。其中CPU主要负责保证帧率,GPU主要负责分辨率相关的一些处理。
据此我们可以把造成游戏性能瓶颈的主要原因分成以下几个方面。
(1)CPU。
过多的draw call。
复杂的脚本或者物理模拟。
(2)GPU。
• 顶点处理:
过多的顶点。
过多的逐顶点计算。
• 片元处理:
过多的片元(即可能是由于分辨率造成的,也可能是由于overdraw造成的)。
过多的逐片元计算。
(3)带宽。
使用了尺寸很大且未压缩的纹理。
分辨率过高的帧缓存。
对于CPU来说,限制它的主要是每一帧draw call的数目,简单来说,就是CPU在每次通知GPU进行渲染之前,都需要提前准备好顶点数据(如位置、法线、颜色、纹理坐标等)。然后调用一系列API把它们放到GPU可以访问到的指定位置,最后调用一个绘制命令来告诉GPU进行渲染。而调用绘制命令的时候就会产生一个draw call。过多的draw call会造成CPU的性能瓶颈,这是因为每次调用draw call时,CPU往往都需要改变很多渲染状态的设置,而这些操作是非常耗时的。如果一帧中需要的draw call数目过多的话,就会导致CPU把大部分时间都花费在提交draw call的工作上面了。当然其他原因也可能造成CPU的瓶颈,例如物理、布料模拟、蒙皮、粒子模拟等,这些都是计算量很大的操作。
而对于GPU来说,他负责渲染整个流水线。它从处理CPU传递过来的模型数据开始,进行顶点着色器、片元着色器等一系列工作,最后输出屏幕上的每个像素。因此GPU的性能瓶颈和需要处理的顶点数目、屏幕分辨率、显存等因素有关。而相关的优化策略可以从减少处理的数据规模(包括顶点数目和片元数目)、减少运算复杂度等方面入手。
本专栏后续的优化技术有:
(1)CPU优化。
使用批处理技术减少draw call数目。
(2)GPU优化。
① 减少需要处理的顶点数目:
优化几何体。
使用模型的LOD技术。
使用遮挡剔除(Occlusion)技术。
② 减少需要处理的片元数目:
控制绘制顺序。
警惕透明物体。
减少实时光照。
③ 减少计算复杂度:
使用Shader的LOD技术。
代码方面的优化。
(3)节省内存带宽:
减少纹理大小。
利用分辨率缩放。
开始优化之前,我们首先要知道是哪个步骤造成了性能瓶颈。而这可以利用unity提供的一些渲染分析工具来实现。
三、unity中的渲染分析工具
unity内置了一些工具,帮助我们方便查看和渲染相关的各个统计数据。这些数据可以帮助我们分析游戏的渲染性能,从而更有针对性地进行优化。在unity5中,这些工具包括了渲染统计窗口(Rendering Statistics Window)、性能分析器(Profiler),以及帧调试器(Frame Debugger)。需要注意的是,在不同的目标平台上,这些工具中显示的数据也会发生变化。
3.1 渲染统计窗口
这个窗口用来显示当前游戏的各个渲染统计变量,我们可以通过在Game视图右上方的菜单中单击Stats按钮来打开它:
可以看出,渲染统计窗口主要包含了3个方面的信息:音频(Audio)、图像(Graphics)和网络(Network)。我们这里只关注第二个方面,即图像相关的渲染统计结果。
渲染统计窗口显示了很多重要的渲染数据,例如FPS、批处理数目、顶点和三角网格的数目等。下表是各个信息数据:
unity5的渲染统计窗口相较于之前版本中的有了一些变化,最明显的区别之一就是去掉了draw call数目的显示,而添加了批处理数目的显示。Batches和Saved by batching更容易让开发者理解批处理的优化结果。当然想要查看draw call的数目等其他更加详细的数据,可以通过unity编辑器的性能分析器来查看。
3.2 性能分析器的渲染区域
可以通过单击Window->Profiler来打开unity的性能分析器(Profiler)。性能分析器中的渲染区域(Rendering Area)提供了更多关于渲染的统计信息,如图:
性能分析器显示了绝大部分在渲染统计窗口中提供的信息,例如draw call数目、动态批处理/静态批处理数目、渲染纹理的数目和内存占用等。
结合渲染统计窗口和性能分析器,我们可以查看与渲染相关的绝大多数重要的数据。性能分析器给出的draw call数目和批处理数目、Pass数目并不相等。并且看起来好像要大于我们估算的数目,这是因为unity在背后需要进行很多工作,例如初始化各个缓存、为阴影更新深度纹理和阴影映射纹理等,因此要花费比预期更多的draw call。unity5引入了一个新的工具来帮助我们查看每一个draw call的工作,这个工具就是帧调试器。
3.3 帧调试器
这个窗口中,我们可以清楚地看到每一个draw call的工作和结果:
帧调试器的调试面板上显示了渲染这一帧所需要的所有的渲染事件,比如本例事件数目为27,而其中包含了24个draw call事件(其他渲染事件多为清空缓存等)。通过单击面板上的每个事件,我们可以在Game视图查看该事件的绘制结果,同时渲染统计面板上的数据也会显示成截止到当前事件为止的各个渲染统计数据。
利用这三个工具的帮助下,我们可以获得很多有用的优化信息。但是很多诸如渲染时间这样的数据是基于当前的开发平台得到的,而非真机上的结果。
3.4 其他性能分析工具
对于移动平台上的游戏来说,我们更希望得到在真机上运行游戏时的性能数据。这时unity目前提供的各个工具就不能再满足我们的需求了。
对于Android平台来说,高通的Adreno分析工具可以对不同的测试机进行详细的性能分析。英伟达提供了NVPerfHUD工具来帮助我们得到几乎所有需要的性能分析数据,例如每个draw call的GPU时间,每个每个shader花费的cycle数目等。
对于IOS平台来说,unity内置的分析器可以得到整个场景花费的GPU时间,PowerVRAM的PVRUniSCo shader分析器也可以给出一个大致的性能评估。Xcode中的OpenGL ES Driver Instrument可以给出一些宏观上的性能信息,例如设备利用率、渲染器利用率等。但相对于Android平台,对IOS的性能分析更加困难(工具少)。而且PowerVR芯片采用了基于瓦片的延迟渲染器,因此想要得到每个draw call花费的GPU时间几乎是不可能的,这时一些宏观上的统计数据可能更有参考价值。
上面主要概述了一些优化技巧,后面的文章会讲述具体的优化方案了。
版权声明:本文为CSDN博主「小橙子0」的原创文章,
遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cgy56191948/article/details/102902759