分为三个部分:Unity官方文档,GDC,个人经验。
Unity Manual
1.计算量优化。着色器进行的计算和处理越多,对性能的影响越大。针对不影响最终效果但依然进行计算的无效代码,进行移除操作。计算的频率也会影响游戏的性能。通常,像素着色器比顶点着色器的执行次数要多。在可能的情况下,将计算从像素着色器移动到顶点着色器,或将它们完全在着色器移除,在脚本中计算并传递给着色器。
2.表面着色器优化。Unity提供的表面着色器非常适合编写与光照交互的着色器。针对特定情况设置关键字以使着色器效率更高或减小体积:
approxview使用逐顶点而不是逐像素的规范化观察向量
。虽然是近似值,通常足够使用。镜面反射着色器类型使用halfasview更快
。计算半角向量并逐顶点进行规范化,并且光照函数使用半角向量而不是观察向量作为参数。noforwardadd
着色器仅完全支持前向渲染中的一个定向光源。其余的光源仍然可以有逐顶点光照或球谐的效果。减少了着色器大小,即使存在多个灯光始终只渲染一次。noambient
禁用着色器的环境光和球谐光照。
3.计算精度优化。当使用CG / HLSL编写着色器时,存在三种基本的数字类型:float(32bits)
,half(16bits)
和fixed(11bits)
- 对于世界空间位置和纹理坐标,使用
float
精度。 - 对于其他一切(矢量,HDR颜色等),首先使用
half精度
,必要时增加精度。 - 对于纹理数据的非常简单的操作,使用
fixed
精度。
实际上,应该使用哪种数据精度取决于平台和GPU。一般来说:
- 所有现代桌面级GPU总是以完全
float精度进行
计算,float/half/fixed
在底层是完全相同的。因此在Unity编辑器中(即使切换为移动平台),难以确定半/固定精度是否足够,因此请始终在目标设备上测试着色器以获得准确的结果。 - 移动GPU具有实际
half精度
支持。通常更快,并且使用更少的功率来进行计算。 Fixed
精度通常仅对较旧的移动GPU有效。大多数现代GPU(支持OpenGL ES 3.0或Metal)内部处理fixed
和half
精度完全相同。
4.Alpha Testing优化。固定函数AlphaTest - 或其可编程等价函数clip()
- 在不同平台上具有不同的性能表现:
- 通常,在大多数平台上使用它来移除的完全透明像素时,有些许性能优势。
- 但是,在iOS和某些使用PowerVR GPU的Android设备上,alpha testing是资源密集型的。不要试图在这些平台上使用它进行性能优化,会导致游戏运行速度比平常慢。
5.Color Mask优化。在某些平台上(主要是iOS和Android设备中的移动GPU),使用ColorMask忽略某些通道(例如ColorMask RGB
)可能是资源密集型的,因此请在必要时才使用。
GDC
GDC2013和GDC2014上介绍了DX10和DX11上PC和Console上的底层着色语言优化,将优化放在减少着色器指令数量上面。
个人认为,在PC和Console平台上对于指令数量的优化意义并不大。但是在移动平台,指令数量的优化还是有必要。虽然SM3.0指令数量已经基本不会对着色器编写复杂度进行限制,但是如果要求支持SM2.0,96条指令数量要求十分严苛。
由于着色器指令的优化与硬件(HW)关系密切,因此我们需要根据硬件厂商提供的相关文档进行优化。移动平台的三大GPU品牌,分别是PowerVR,Mali,Adreno。PowerVR有专门的GLSL优化文档,Mali和Adreno也有相关文档提到这部分内容。
但这样做,必然会增加着色器变体数量,因为我们要使用关键字来选择执行不同的代码,这会生成不同的着色器变体。
根据PowerVR Low Level GLSL Optimisation,我这里列举一些优化的方式。至于Mali和Adreno的优化,需要参考其开发文档进行。
通常来讲,在PowerVR上的Shader性能取决于执行Shader的周