原文链接
版权声明:本文为CSDN博主「凯奥斯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
正文
在 Shader山下(二十)编译指令(Compilation Directives) 中给大家介绍了如何使用编译指令,下面这篇文章就专门给大家介绍一下多重编译(multi_compile)指令。
multi_compile
我们可以使用 multi_compile 来为 shader 创建多个稍微有点区别的 shader 变体。这个 Shader 被称为宏着色器(mega shader)或者超着色器(uber shader)。
实现原理
根据不同的情况,使用不同的预处理器指令,来多次编译 Shader 代码。
在 Unity 里面,可以使用两个指令来实现。适用于 VF 着色器和表面着色器:
#pragma multi_compile #pragma shader_feature
运行时,会根据 材质(Material)的关键字(Material 的对象方法 EnableKeyword 和 DisableKeyword)或者 全局着色器 关键字(Shader 的类方法 EnableKeyword 和 DisableKeyword)。
注: 之前在 Shader入门(十二)材质属性绘制器 里,我们已经介绍了多重编译的运用
使用 multi_compile 指令
#pragma multi_compile TEST_OFF TEST_ON
这样会编译两个 Shader 变体,
- 一个是
TEST_OFF的版本, - 一个是
TEST_ON的版本。
运行的时候会根据 材质关键字 或者 Shader 全局关键字 判断应该使用哪个,如果两个关键字都为 false,那么会使用第一个(TEST_OFF)变体。
我们也可以创建 多个 关键字:
#pragma multi_compile TEST_A TEST_B TEST_C TEST_D
或者只创建 一个 关键字,这时候就需要使用 __ 来代替另一个:
#pragma __ TEST_KEY_ON
这样依然会生成两个 shader 变体,一个啥都没定义,另外一个定义了TEST_KEY_ON。
我们还可以通过 多行指令 来组合关键字:
#pragma multi_compile A B C
#pragma multi_compile D E
这样就会生成 6 个 shader 变体(A+D、B+D、C+D、A+E、B+E、C+E)。但是这样 shader 变体的数量就可能会变得很多
例子 1:
第一行 2 个关键字 +
__,第二行 1 个关键字 +__,那么就有 3x2 = 6 种例子 2:
10 行
multi_compile,每行有两个关键字,那么就会有 1024 个 shader 变体。
shader_feature
除了 multi_compile 之外,还有另外一个类似的指令 shader_feature ,唯一的区别 在于 shader_feature 不会将 不用的 shader 变体添加到程序中去。
shader_feature更适用于 材质的关键字,- 而
multi_compile更适用于代码设置的 全局关键字。
示例:
#pragma shader_feature TEST_STUFF
这是下面这种写法的简写形式:
#pragma shader_feature __ TEST_STUFF
注: Unity 中最多可以有 128 个关键字,但是 Unity 自己已经定义了一部分了,所以实际上会更少。所以使用
multi_compile和shader_feature的时候,就需要特别注意不要超过这个限制。
Unity 内建一些 multi_compile 的快捷写法
| 标题 | 说明 |
|---|---|
multi_compile_fwdbase | 为 基本前向渲染通道 编译多个变体,不同的变体可能需要处理不同的光照贴图类型,或者一些使用了主平行光的阴影,而另一些禁用了。(参考 Unity 渲染管线) |
multi_compile_fwdadd | 为 附加前向渲染通道 编译多个变体,不同的变体可能需要处理不同类型的光源 —— 平行光、聚光灯或者点光源,亦或者它们附带 cookie 纹理的版本。 |
multi_compile_fwdadd_fullshadows | 同上,不过包含了可以让光源拥有 实时阴影 的功能。 |
multi_complie_fog | 为处理不同的 雾效 类型(off/linear/exp/exp2)扩展了多个变体。 |
大部分内建快捷写法会 导致 许多 shader 变体,如果某些不需要使用,那么可以使用
#pragma skip_variants来忽略它们。
#pragma multi_compile_fwdadd
// will make all variants containing "POINT" or "POINT_COOKIE" be skipped
#pragma skip_variants POINT POINT_COOKIE
硬件变体
使用 multi_compile 的 目的 一般是为了创建一些 fallback 或者简化 shader,它们在同一个目标平台(例如 OpenGL ES)的 高端硬件 和 低端硬件 上都可以高效地运行。这种时候,我们可以使用 shader 硬件变体来为 不同性能等级的硬件 创建一个特殊优化的变体集合。
为了生成 shader 硬件变体,需要添加 #pragma hardware_tier_variantsrenderer,这里 renderer 表示某个可运行的渲染平台。使用这个指令,Unity 会对每个 shader 生成 3 个 shader 变体(其他关键字会不起作用),而对应的关键字是:
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
在编辑器里,可以通过 Graphics Emulation 菜单来测试他们。
注: 这些 shader 并不受 Quality Setting 的影响,它们纯粹是通过检测 GPU 的相关性能来决定的。
URP 的阴影变体
_MAIN_LIGHT_SHADOWS_MAIN_LIGHT_SHADOWS_CASCADE_ADDITIONAL_LIGHTS_VERTEX_ADDITIONAL_LIGHTS_ADDITIONAL_LIGHT_SHADOWS_SHADOWS_SOFT_MIXED_LIGHTING_SUBTRACTIVE