《Unity Shader入门精要》笔记(三十二)
本文为《Unity Shader入门精要》第十六章《Unity中的渲染优化技术》的上半部分内容《Unity中的渲染分析工具》。本文相关代码,详见:
原书代码,详见原作者github:
<hr/>建立认知:
游戏优化不仅是程序员的工作,更需要美工人员在美术上进行一定的权衡。
举例:
[*]URP渲染管线,让美术使用SimpleLit,而不是Lit;
[*]用图片+Animation代替粒子系统;
[*]降低模型中不必要的网格数;
[*]减少透明混合造成overdraw等。
1. 移动平台的特点
相比PC平台,移动平台的特点:资源有限、带宽更小。
一些基于GPU架构的优化:
[*]为移除一些隐藏的表面,减少overdraw(同一像素绘制多次),PowerVR芯片(用于iOS设备和一些Android设备)使用基于瓦片的延迟渲染(Tiled-based Deferred Rendering, TBDR)架构,把所有渲染图像装入一个个瓦片中,由硬件找到可见的片元,并只对它们执行片元着色器;
[*]另一些基于瓦片的GPU架构,如:Adreno(高通的芯片)和Mali(ARM的芯片),使用Early-Z或相似的技术进行低精度的深度检测,剔除不需要渲染的片元。
Android平台:
差异比较明显,不同设备使用不同的硬件,如:图形芯片、屏幕分辨率等,这对图形优化剔除更高的挑战。
iOS平台:
硬件条件相对统一。
2. 影响性能的因素
造成游戏性能瓶颈的主要原因:
[*]CPU
[*]过多的Draw Call;
[*]复杂的脚本或物理模拟;
[*]GPU
[*]顶点处理
[*]过多的顶点
[*]过多的逐顶点计算
[*]片元处理
[*]过多的片元(可能是分辨率高造成的,也可能是overdraw造成的);
[*]过多的逐片元计算
[*]带宽
[*]使用了尺寸很大且未压缩的纹理
[*]分辨率过高的帧缓存
2.1 CPU层面
限制性能的主要因素是Draw Call的数目。
Draw Call在CPU层面都做了什么:
[*]CPU每次通知GPU渲染前需要提前准备好顶点数据(如:位置、法线、颜色、纹理坐标等);
[*]调用一系列API把顶点数据放到GPU可访问的指定位置;
[*]调用一次绘制命令(产生一次Draw Call);
每次调用Draw Call,CPU往往需要改变很多渲染状态的设置,这些操作非常耗时。过多的Draw Call会导致CPU把大部分时间花费在提交Draw Call的准备工作上,导致性能下降。
其他可能造成CPU瓶颈的原因:物理、布料模拟、蒙皮、粒子模拟 等。
2.2 GPU层面
GPU负责整个渲染流水线。它从处理CPU传递过来的模型数据开始,进行顶点着色器、片元着色器等一系列工作,最后输出屏幕上的每个像素。因此性能瓶颈与需要处理的顶点数目、屏幕分辨率、显存等因素有关。
相关优化策略可以从减少处理的规模(顶点数目、片元数目)、减少匀速复杂度等方面入手。
后续涉及的优化技术:
[*]CPU优化
[*]使用批处理技术减少Draw Call数目;
[*]GPU优化
[*]减少需要处理的顶点数目
[*]优化几何体
[*]使用模型的LOD技术
[*]使用遮挡剔除技术
[*]减少需要处理的片元数目
[*]控制绘制顺序
[*]警惕透明物体
[*]减少实时光照
[*]减少计算复杂度
[*]使用Shader的LOD技术
[*]代码方面的优化
[*]节省内存带宽
[*]减少纹理大小
[*]利用分辨率缩放
3. Unity中渲染分析工具
Unity中有3个工具可以帮我们分析游戏性能:
[*]渲染统计窗口(Render Statistics WIndow)
[*]性能分析器(Profiler)
[*]帧调试器(Frame Debugger)
3.1 渲染统计窗口
在Unity Game窗口工具栏的Stats按钮点开后会弹出数据统计窗口,里面的Graphics区域(图中黄框选中区域)是我们需要关注的渲染统计窗口,里面显示了很多渲染相关的数据。
[*]FPS(每帧耗时)
FPS(Frame per Second),每秒的帧数,后面的括号中显示的是当前帧的耗时。
[*]CPU:main / render thread
main后面跟的是主线程的耗时,render thread跟的是渲染线程的耗时。
[*]Batches
当前帧需要进行的批处理数目。
[*]Saved by batching
合并的批处理数目,这个数字表明了批处理为我们节省了多少Draw Call。
[*]Tris / Vertes
当前帧绘制的三角面片和顶点的数目。
[*]Scene
屏幕的大小,及它占用的内存大小。
[*]SetPass calls
渲染使用的Pass的数目,每个Pass都需要Unity的runtime来绑定一个新的Shader。数目越大,越容易产生CPU的性能瓶颈。
[*]Shadow caster
在有光照的前提下,在相机的视椎体范围内,有多少物体具备投射阴影的能力。
[*]Visible skinned meshes
渲染的蒙皮网格数目。
[*]Animations
播放的动画数目。
Batches和Saved by batching更容易让开发者理解批处理的优化结果。渲染统计面板仅提供粗略的数据,更详细的数据需要在性能分析器中查看。
3.2 性能分析器的渲染区域
在Unity的菜单栏,依次点击Window-Analysis-Profiler可打开性能分析器面板,或者直接按快捷键Ctrl + 7直接打开:
上图选中的是渲染(Rendering)相关的统计信息,统计信息分上下两部分,上半部分显示的是实时渲染信息,例如:绿线显示了批处理的数目、蓝线显示了Pass数目等,而下半部分显示的是选中的某一帧中更详细的信息,例如:Draw Call数目、动态批处理/静态批处理的数目、渲染纹理的数目和内存占用等。
需要注意的是:
Unity Engine中运行的游戏,因为引擎编辑器自身运行需要一定的开销,使用性能分析器分析得到的数据往往不具有参考意义。所以我们一般会在真实运行设备(例如:Android手机等)上去分析游戏的性能,这时的性能分析器展示的数据才是真实准确的。且设备上的游戏包体需要在打包时勾选Development Build:
移动端真机链接性能分析器的方法有2种,分别是:局域网、USB数据线连接。
[*]局域网
保证运行设备和PC在相同的网络环境下(比如:连相同的wifi),打开性能分析面板,点击Play Mode下拉框,此时下拉框中就会显示当前网络环境下正在运行当前游戏的设备,选中自己的设备即可进行联机调试。
[*]USB数据连接
开启设备上的开发者模式,并启用USB调试,将设备通过USB数据线连接PC,选择文件传输模式。然后打开性能分析面板,点击Play Mode下拉框,选择<Enter IP>,输入手机在当前网络环境下的IP,Unity Engine会自动遍历设备上运行的所有服务端口,找到正在运行的要调试的游戏,然后性能分析面板上就会实时出现游戏的性能数据。
3.3 帧调试器
在Unity的菜单栏,依次点击Window-Analysis-Frame Debugger可打开帧调试器面板,在面板中点击Enable按钮,即可得到运行的游戏在当前帧的渲染情况。
从上图左侧的列表中,从上往下框住的黄色区域分别为:绘制深度纹理、阴影投射与接收、渲染场景中的模型网格、雾效的屏幕后处理。选中左侧对应列表项,右侧区域会展示选中的绘制事件的详细信息,包括:使用的Shader、对应的Pass、关键词、使用到的纹理、向量等。
更详细的帧调试器的使用,感兴趣的小伙伴可以在网上自行查阅。
基于上面3种Unity自带的调试工具,我们可以解决绝大部分的性能瓶颈。当然为了更精确更细致的获取游戏的性能数据,有时我们也需要其他性能分析工具的介入。
3.4 其他性能分析工具
[*]Android平台
[*]高通的Adreno分析工具:对不同的测试机进行详细的性能分析。
[*]英伟达的NVPerfHUD工具:帮助我们得到几乎所有需要的性能分析数据,如:每个Draw Call的GPU时间、每个Shader花费的cycle数目等。
[*]iOS平台
[*]PowerVRAM的PVRUniSCo Shader分析器:给出大致的性能评估。
[*]XCode的OpenGL ES Driver Instruments:给出一些宏观上的性能信息,如:设备利用率、渲染器利用率等。
相比Android,对iOS的性能分析更加困难(工具较少)。且PowerVR芯片采用了基于瓦片的延迟渲染器,想得到每个Draw Call花费的GPU时间几乎不可能,所以一些宏观上的统计数据更有参考价值。
以上是本次笔记的所有内容,下一篇笔记我们将继续学习渲染优化,了解性能优化方法的相关知识。
<hr/>
写在最后
本文内容会同步发在笔者的公众号上,欢迎大家关注交流!
公众号:程序员叨叨叨(ID:i_coder)
页:
[1]