Cg/HLSL中3种精度的数值类型
类型 | 精度 |
float | 最高精度的浮点值。通常使用32位来存储 |
half | 中等精度的浮点值。通常使用16位来存储,精度范围是-60000~+60000 |
fixed | 最低精度的浮点值。通常使用11位来存储,精度范围是-2.0~+2.0 |
尽管有上面的不同,但一个基本建议是,尽可能使用精度较低的类型,因为这可以优化Shader的性能,这一点在移动平台上尤其重要。从它们大体的值域范围来看,我们可以使用fixed类型来存储颜色和单位矢量,如果要存储更大范围的数据可以选择half类型,最差情况下再选择使用float。如果我们的目标平台是移动平台,一定要确保在真实的手机上测试我们的Shader,这一点非常重要。
规范语法
DirectX平台对Shader的语义有更加严格的要求。这意味着,如果我们要发布到DirectX平台上就需要使用更严格的语法。例如,使用和变量类型相匹配的参数数目来对变量进行初始化。
避免不必要的计算
如果我们毫无节制地在Shader(尤其是片元着色器)中进行了大量计算,那么我们可能很快就会收到Uity的错误提示:
temporary register limit of 8 exceeded
或
Arithmetic instruction limit of 64 exceeded; 65 arithmetic instructions needed to compile program
出现这些错误信息大多是因为我们在Shader中进行了过多的运算,使得需要的临时寄存器数目或指令数目超过了当前可支持的数目。不同的Shader Target、不同的着色器阶段,我们可使用的临时寄存器和指令数目都是不同的。
通常,我们可以通过指定更高等级的Shader Target来消除这些错误。
Unity支持的Shader Target
指令 | 描述 |
#pragma target 2.0 | 默认的Shader Target等级。相当于Direct3D 9上的Shader Model 2.0,不支持对顶点纹理的采样,不支持显式的LOD纹理采样等 |
#pragma target 3.0 |
相当于Direct3D 9上的Shader Model 3.0,支持对顶点纹理的采样等 |
#pragma target 4.0 |
相当于Direct3D 10上的Shader Model 4.0,支持几何着色器等 |
#pragma target 5.0 |
相当于Direct3D 11上的Shader Model 5.0 |
什么是Shader Model呢?
Shader Model是由微软提出的一套规范,通俗地理解就是它们决定了Shader中各个特性(feature)的能力(capability)。这些特性和能力体现在Shader能使用的运算指令数目、寄存器个数等各个方面。Shader Model等级越高,Shader的能力就越大。
虽然更高等级的Shader Target可以让我们使用更多的临时寄存器和运算指令,但一个更好的方法是尽可能减少Shader中的运算,或者通过预计算的方式来提供更多的数据。
慎用分支和循环语句
在最开始,GPU是不支持在顶点着色器和片元着色器中使用流程控制语句的。随着GPU的发展,我们现在已经可以使用if-else、for和while这种流程控制指令了。但是,它们在GPU上的实现和CPU上有很大的不同。大体来说,GPU使用了不同于CPU的技术来实现分支语句,在最坏的情况下,我们花在一个分支语句的时间相当于运行了所有分支语句的时间。因此,我们不鼓励在Shader中使用流程控制语句,因为它们会降低GPU的并行处理操作(尽管在现代的GPU上已经有了改进)。
如果我们在Shader中使用了大量的流程控制语句,那么这个Shader的性能可能会成倍下降。一个解决方法是,我们应该尽量把计算向流水线上端移动,例如把放在片元着色器中的计算放到顶点着色器中,或者直接在CPU中进行预计算,再把结果传递给Shader。当然,有时我们不可避免地要使用分支语句来进行运算,那么一些建议是:
不要除以0