【转载】Shader 山下(二十一)多重变体(Multiple Variants)

192 阅读4分钟

原文链接

版权声明:本文为CSDN博主「凯奥斯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:blog.csdn.net/ecidevilin/…

正文

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 的对象方法 EnableKeywordDisableKeyword)或者 全局着色器 关键字(Shader 的类方法 EnableKeywordDisableKeyword)。

注: 之前在 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 变体的数量就可能会变得很多

例子 1Variant_Combination.png 第一行 2 个关键字 + __,第二行 1 个关键字 + __,那么就有 3x2 = 6 种

例子 2

10multi_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_compileshader_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

Feature.png

Variant.png

ShadowCaster.png