变体相当于条件判断,当然简单的数值判断可以用step直接代替,这个不提
但是if条件判断对于Shader来说不是一个有效率的方法,为什么说if不好呢?因为GPU是并行计算的,保证一样的执行顺序是有利于GPU的。而当你使用if时,同一段代码的运行顺序与时间就会随着情况的不同而发生变化,这是非常不适合并行计算的。
PS:这套理论貌似在现在的GPU上不适合了,step甚至有时候会比if费
而变体通过Define可以做到,它的原理就是在编译时自动产生多种Shader的变体,根据你在Shader里Define的数量,就会产生多少数量的Shader。再根据你开启哪個Define的功能來运行对应的Shader。
multi_compile 后面的叫Keyword,Keyword的数量是有限制的,最多是256個,但是Unity本身已经预设了不少,所以使用要特別注意数量上限。
Keyword默认第一个开启,下面是一个简单的测试
#pragma multi_compile COLOR_A COLOR_B
fixed4 frag (v2f i) : SV_Target
{
fixed4 col;
#ifdef COLOR_A
col = _ColorA;
#elif COLOR_B
col = _ColorB;
#endif
return col;
}
如果换一下 Keyword位置
#pragma multi_compile COLOR_B COLOR_A
当然,也可以用脚本控制
Material.EnableKeyword("COLOR_B");
Material.DisableKeyword("COLOR_B");
shader_feature是multi_compile的一个子集。 但是shader_feature是在材质球面板就決定好了要使用的变体,未使用的会在编译时舍去
看一下unity 自带的材质就懂了
MaterialPropertyDrawer 相当于脚本里的属性标签
用Toggle
[Toggle] _Color("ColorA ? ", Float) = 0
#pragma multi_compile __ _COLOR_ON
或者#pragma shader_feature _COLOR_ON
fixed4 frag (v2f i) : SV_Target
{
fixed4 col;
#ifdef _COLOR_ON
col = _ColorA;
#else
col = _ColorB;
#endif
return col;
}
如果标签内不指定Keyword的名称,就按变数名大写 + _ON命名
用KeywordEnum
[KeywordEnum(A,B)] _Color("ColorA ? ", Float) = 0
#pragma multi_compile _COLOR_A _COLOR_B
或者#pragma shader_feature _COLOR_A _COLOR_B
fixed4 col;
#ifdef _COLOR_A
col = _ColorA;
#else
col = _ColorB;
#endif
return col;
其他还有很多细节,可以直接去看官方文档,就不说了。。
真的很有用啦这个东西