目标
既然要优化,肯定要有个目标:
pc上一般要求:一秒渲染60帧
移动端:一秒渲染30帧
这应该是最低的要求,如果游戏运行时,游戏帧率有变化,人眼能够明显的感觉到帧率下降。
优化的首要规则是找到性能问题的所在。
一般出现问题不是在cpu就是gpu。
profiler
unity内置了性能检测工具,
可以在Window->Analysis->Profiler 打开,由于在编辑器内调试准确率有问题,一般推荐打包调试
打包调试记得开启调试模式,并开启自动连接调试器并支持深度调试,这样等打包完成自动打开场景时,unity会自动连接profiler,省得我们自己去连接。
上图为跑了一些帧后的每帧时间占用。
我们还可以在这里切换成Hierarchy模式查看每个函数列表耗时。当你选择函数时,上面图标也会高亮相关内容。
这一块可以看到每一部分占用的时间,左侧为什么类型,右侧是占用时间的变化,点击选择一帧。
在下面会看主要分了三大部分,这一帧总耗时16.74ms
左侧是代码逻辑部分占用时间,我这个测试项目没有多少逻辑占用,所以性能占用很少。中间这一部分是调用渲染占用时间,可以看到占用了2.15ms,然后是最后的同步占用时间13.61ms。相当于电脑可以一直按满帧率去跑。
如果脚本的问题话,需要让程序去排查,TA一般需要查看右边的两部分问题。
多线程的我们还可以看到渲染线程给我们分出来了,让我们查看渲染线程做的操作。灰色的部分是在等待主线程耗时上面会显示Gfx.WaitForGfxCommandsFromMainThread,而蓝色部分为实际渲染时的批次提交耗时。而在urp渲染管线,后处理的操作是在主线程做的。
上图可以看到,应该是我开启了垂直同步,导致同步时间过长,如果在排查问题,推荐将垂直同步关闭。让其使用最大性能运算。
上图为关闭了垂直同步后的视图,为每帧真实的渲染时间。但是你看画面会有撕裂感,这也是垂直同步带来的好处,调试时,我们是可以关闭的。
每帧渲染
在cpu上,每帧需要处理的事情:
- 逻辑相关:脚本,物理,动画
- 渲染:剔除,排序,绘制
- DrawCall包含了单个玩个的数据以及相关的渲染信息纹理矩阵等,然后提交渲染的命令
- SetPassCall用来设置用于渲染网格材质的所有渲染状态数据,
- Batches是包含了一个共享顶点和索引的缓冲区数据包,不用提交顶点数据,速度很快,批处理的意义在于减少了渲染状态的切换,它不能减少DrawCall,但是可以减少其它状态的切换,相对来说调用DrawCall的耗时比SetPassCall耗时更少。
- 同步:同步的问题一般会有垂直同步和帧率限制的问题,同步时都会有等待的状态,
- 垂直同步是在你的渲染帧率高于屏幕显示器最高帧率时,它会自动限制帧率和显示器保持同步。
- 帧率限制也是为了保证每秒的帧率平衡,不产生撕裂感。
- 如果同步里出现WaitForTargetFPS,是因为垂直同步的问题,调试时不建议开启。
- 如果出现GfxDeviceD3D11.WaitForLastPresent,表明CPU所有线程已经完成任务,正等待CPU,可能存在gpu性能瓶颈。
- 如果出现Gfx.WaitForPresentOnGfxThread,表示主线程已经完成非渲染任务,正在等待渲染线程,但渲染线程尚未完成。1. 若此时渲染线程正在进行Camera.Render,并且Camera.Render耗时过高,则表明性能瓶颈在cpu端渲染部分。2. 若此时渲染线程正在进行Gfx.PresentFrame,则表明性能瓶颈在gpu端。
在gpu上,影响gpu渲染效率的是像素填充率(filling rate),填充率=屏幕像素Shader复杂度Overdraw,可以影响到效率的主要内容有:
- 屏幕分辨率
- 后处理效果
- Shader复杂度
- Overdraw 重复绘制,指屏幕的同一像素进行多次绘制,一般是因为
- 带宽瓶颈:内存带宽是指gpu可以读取和写入内存的速率。当gpu当前渲染数量太大,内存无法及时传输给gpu,会造成等待耗时。常见情况在延迟渲染中常驻Gbuffer及各种缓冲区和RT,占用内存非常大,并且一直在读写。移动平台gpu的带宽性能和纹理处理能力比较低,需要注意此问题,这也是移动端很少使用延迟渲染的原因。
- 同屏三角面数,顶点数,为什么顶点的影响小,可以这样计算,一张1k的图片就是一百万个像素,而一百万个顶点的模型我们很少用。
总结一下:区分问题哪里的问题看同步的那几个函数,而在gpu上,主要看像素的计算量,屏幕分辨率是主要原因,屏幕像素渲染量是指数增加,后处理也是基于屏幕分辨率计算的,而半透明是因为模型所处的区域全部需要绘制,因为它的渲染顺序是基于相机的位置从远到近绘制的,没有被半透明遮挡的位置全部需要绘制。我们可以感觉到gpu上的计算量非常的大,毕竟每个像素都需要跑一次片元着色器内的内容。
性能分析工具
- unity内置的Profiler 上面讲的
- FrameDebugger 帧调试器,主要渲染效果调试,查看当前每帧渲染的内容
- FPS Counter 场景组件,可以直接添加到场景内,查看渲染情况
- UPR unity官方提供的性能工具 UWA 第三方专业做性能的公司
- RenderDoc 截帧工具 XCode 是ios平台使用的调试工具,一般调试苹果手机使用
场景优化
- 场景结构,层级推荐不要太复杂,动态生成的直接放在Root下面。
- 尽量使用Profab,而不是直接使用GameObject。
- Shader通用一套,保证物体使用同一个Shader,这是合批的前提。
- LightMap推荐2048,数量太多会影响合批。
- 检查ReflectionProbe,它也会影响合批
- 对静态物体尽量保证材质球共有,图片合并
- 对大量的树,草,石头使用GPU Instancing
- 检查剩余物体是否能够srp合批。
- 检查最终资源的是否有占用过大的情况
- 根据同屏面数确定是否使用LOD
- 优化场景Shader以及光照和阴影设置。