CPU:
过多的DrawCall
复杂的脚本或者物理模拟
GPU:
顶点处理:
过多的顶点
过多的逐顶点计算
片源处理:
过多的片元(极可能是由于分辨率造成的,也可能是由于overdraw造成的)
过多的逐片元计算
带宽:
使用了尺寸很大且未压缩的纹理
分辨率过高的帧缓存
CPU优化之批处理:
什么样的物体可以一起处理?答:使用同一个材质的物体。他们之前的不同仅仅在于顶点数据的差别。
动态批处理:一些模型共享了同一个材质并且满足一些条件。
动态批处理原理:每一帧吧可以进行批处理的模型网格进行合并,再把合并后模型数据传递给GPU,然后使用同一个材质进行渲染。
注意:
1.能够进行动态批处理的网格顶点属性规模要小于900。例如,如果shader中需要使用顶点位置、法线和纹理坐标这3个顶点属性,那么如果想要模型进行批处理,模型的顶点数量不能超过300。
2.顶点属性规模符合并且使用同一材质,缩放不为负数那么他们可以被动态合批
3.使用光照纹理(lightmap)的物体需要小心处理。这些物体需要额外的渲染参数,例如,光照索引,偏移量,缩放信息等。因此,为了让这些物体可以被动态批处理,我们需要保证他们指向光照纹理中的同一个位置。
4.多pass的shader会中断批处理。在前向渲染中,我们有时需要使用额外的pass来为模型添加更多的光照效果,但这样一来模型就不会被动态批处理了。
静态批处理:
缺点:不可被移动,会增大内存
静态批处理原理:在运行开始阶段,把需要进行静态批处理的模型合并到一个新的网格结构中,这意味着这些模型是不可以在运行时刻被移动。但由于它只需要进行一次合并操作,因此,比动态合批更加高效。静态合批的的另一个缺点在于,它往往需要占用更多的内存来存储合并后的几何结构。这是因为如果在静态合批处理前一些物体共享了相同的网格,那么在内存中每个物体都会对应一个该网格的复制品,即一个网格会变成多个网格再发给GPU。例如,如果再一个使用1000个相同树模型的森林中使用静态批处理,那么,就会多使用1000倍的内存
共享材质:
无论动态批处理还是静态批处理,都要求模型之间需要共享一个材质。但不同的模型之间总会需要不同的渲染属性,例如,使用不同的纹理颜色、等。这时,我们需要一些策略来尽可能合并材质。
如果两个材质之间只有纹理不同,我们可以把这些纹理合并到一张图集中。
需要注意的地方:
由于批处理是把多个模型变换到世界空间下再合并它们,因此,如果shader中存在一些基于模型空间下的坐标运算,那么往往会得到一个错误的结果。解决办法,再shader中使用DisableBatching标签来强制使该shader的材质不会被批处理
另一个需要注意的地方是,使用半透明材质的物体通常需要使用颜色的从后往前的绘制顺序来保证透明混合的正确性。unity会优先保证他们的绘制顺序,再合批处理,意味着无法满足绘制顺序时,批处理无法再这些物体上被成功应用。
Profiler-GPU参数介绍
SetPassCalls:切换shader Pass的次数,消耗CPU
Batches:批处理次数
Tris:三角面数量
Verts:顶点数量
Used Textures:使用贴图数量
RenderTextures:RT数量
VBO:顶点缓冲对象 一般静态合批后此参数会变大
减少需要处理的片元数目(GPU优化):
重点在于减少overdraw(同一个像素被绘制了多次)。
控制绘制顺序,尽量使用不透明渲染队列(不透明渲染队列从前往后绘制,透明渲染队列从后往前绘制),手动排序渲染顺序(排序思量可以节省掉很多渲染时间)
时刻警惕透明物体:
对于半透明对象来说,由于他们没有开启深度写入,因此,如果要得到正确的渲染效果,就必须从后往前渲染。这意味着,半透明物体几乎一定会造成overdraw。如果不注意这点会在一些机器上造成严重的性能下降。
例如:对于GUI对象来说,他们大多是多设置成了半透明,如果屏幕中GUI占比多,而且有没有用专用的UI相机而是用的主相机,那么GUI就会造成大量的overdraw。
因此,如果场景中包含了大面积的半透明对象,或者有很多层相互狻盖的半透明对象(即便 它们每个的面积可能都不大),或者是透明的粒子效果,在移动设备上也会造成大报的 overdraw。 这是应该尽址避免的。
利用分辨率缩放:Unity3D研究院之使用Android的硬件缩放技术优化执行效率 | 雨松MOMO程序研究院
减少计算复杂度:LOD技术,代码方面优化
对象数<顶点数<像素数
尽可能使用低精度浮点数值进行运算。
最高精度的float/highp适用于储存顶点、坐标等变量,但是由于计算速度是最慢的,我们尽量避免在片元着色器中使用
half/mediump使用一些标量、纹理坐标等变量,它的计算速度大约是float的两倍。
fixed/lowp适用于绝大多数颜色变量和归一化后的方向变量,在进行一些对精度要求不高的计时,计算速度是float的4倍,但要避免对这些低精度变量进行频繁的swizzle操作(如color.xwxw),尽量避免在不同精度之间的转换,这可能会造成性能下降
对于大多数GPU来说,在使用插值寄存器把数据从顶点着色器传递给下一个阶段时,我们应该使用尽可能少的插值变量。例如,如果需要对两个纹理坐标进行插值,我们通常会把它们打包在同一个float4类型的变量中,两个纹理坐标分别对应了xy分量和zw分量,PowerVR例外
尽可能不要使用分支语句和循环语句
尽可能避免使用类似sin、tan、pow、log、等较为复杂的数学运算。可以使用查表来代替
尽可能不要使用discard操作,因为可能会影响硬件的某些优化
可以使用画质分级
其他性能分析工具
对于移动 平台上的游戏来说,我们更希望得到在真机上运行游戏时的性能数据。这时, Unity 目前提供的各个工具可能就不再能满足我们的需求了。 对于 Android 平台来说,高通的 Ad.reno 分析工具可以对不同的测试机进行详细的性能分析。 英伟达提供了 NV1油fHUD工具来帮助我们得到几乎所有需要的性能分析数据,例如,每个 draw call 的 GPU 时间,每个 shader 花费的 cycle 数目等。 对千 iOS 平台来说,Unity 内置的分析器可以得到整个场景花费的 GPU 时间。PowerVRAM 的 PVRUniSCo shader 分析器也可以给出一个大致的性能评估。Xcode 中的 OpenGL ES Driver Instruments 可以给出一些宏观上的性能信息,例如,设备利用率、渲染器利用率等。但相对于 Android 平台,对 iOS 的性能分析更加困难(工具较少)。而且 PowerVR 芯片采用了基千瓦片的 延迟渲染器,因此,想 要得到每个 draw call 花费的 GPU 时间是几乎不可能的。这时,一些宏观 上的统计数据可能更有参考价值。 一 些 其他的性能分析工具可以在 Unity 的官方手册C http://docs.llllity3d.com/Manual/ MobileProfiling.htm I) 中找到。当找到了性能瓶颈后,我们就可以针对这些方面进行特定的优化。