美文网首页
[Unity/shaderlab]关于着色器变体

[Unity/shaderlab]关于着色器变体

作者: 江枫枫Maple | 来源:发表于2019-06-26 18:11 被阅读0次

      在Unity中可以通过#pragma multi_compile或者#pragma shader_feature指令来实现着色器多样化。
      在运行时,相应的着色器变体是从材质的关键词中取得的(Material.EnableKeyword和 DisableKeyword),或者全局着色器关键词(Shader.EnableKeyword和 DisableKeyword)。

0.如何查看shader使用了多少变体?

      在shader的inspector面板中可以看到shader的Compiled code选项,点开之后有一个变体数量查看。


查看变体数量
详细的变体分析

1.multi_compile的用法简析

      如果使用了下面的语法,也就表示定义了两个变体,TEST_OFF和TEST_ON。在运行时,其中的一个将被激活,根据材质或者全局着色器关键词(#ifdef TEST_OFF之类的宏命令也可以)来确定激活哪个。若两个关键词都没有启用,那么将默认使用前一个选项,也就是关闭(OFF)的选项TEST_OFF。

#pragma multi_compile TEST_OFF TEST_ON
上述代码变体数量

     当#pragma multi_compile中存在所有名字都是下划线的一个指定段时,就表示产生一个空的着色器变种。这种做法在着色器编写中比较常见,因为这样可以节省了一个变量个数的占用(下面会提到,Unity中关键词个数是有129个的数量限制的)。例如,下面的指令将产生两个着色器变体;第一个没有定义,第二个定义为TEST_ON:

#pragma multi_compile __ TEST_ON
上述代码变体数量

     我们也可以同时创建多个变体,就像下面这样:

#pragma multi_compile TEST_A TEST_B TEST_C
上述代码变体数量

     此外,我们还可以使用多行指令对变体进行组合,但是这样做的话,会导致变体数量成倍的增长,如果使用下面的代码生成变体,那么我们会得到3*2=6种不同的变体:

#pragma multi_compile TEST_A TEST_B TEST_C
#pragma multi_compile TEST_D TEST_E
上述代码变体数量

2.shader_feature的用法简析

      shader_feature的用法与multi_compile大致相同,唯一的区别在于shader_feature不会将不用的shader变体添加到程序中去。shader_feature更适用于材质的关键字,而multi_compile更适用于代码设置的全局关键字。
     下面两种代码是一样的,第一行是第二行代码的简略版,效果是相同的。

#pragma shader_feature TEST_A
#pragma shader_feature __ TEST_A
上述代码变体数量

      这里我们明明声明了TEST_A变体,但是实际上变体列表中却什么都没有,这是因为我们在查看的时候忽略掉了没有用到的变量:

忽略没有使用的shader_features

      那么我们该怎么启用对应的变体呢?在运行时,相应的着色器变体是从材质的关键词中取得的(Material.EnableKeyword和 DisableKeyword),或者全局着色器关键词(Shader.EnableKeyword和 DisableKeyword)。
      所以我们添加以下代码,并将测试用的材质放在上面,这个时候在运行游戏,我们可以在frame debugger中查看渲染时shader使用的变体,也可以在之前的inspector面板上查看现在拥有的变体数量:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class test : MonoBehaviour {
    public Material mat;
    // Use this for initialization
    void Start()
    {
        mat.EnableKeyword("TEST_A");
    }
}
frame debugger中查看启用的keywords 运行时的变体数量

3.unity内置的变体

multi_compile_fwdbase

      此指令表示,编译正向基础渲染通道(用于正向渲染中,应用环境光照、主方向光照和顶点/球面调和光照(Spherical Harmonic Lighting))所需的所有变体。这些变体用于处理不同的光照贴图类型、主要方向光源的阴影选项的开关与否。

multi_compile_fwdadd

      此指令表示, 编译正向附加渲染通道(用于正向渲染中;以每个光照一个通道的方式应用附加的逐像素光照)所需的所有变体。这些变体用于处理光源的类型(方向光源、聚光灯或者点光源),且这些变种都包含纹理cookie。

multi_compile_fwdadd_fullshadows

      此指令和上面的正向渲染附加通道基本一致,但同时为上述通道的处理赋予了光照实时阴影的能力。

multi_compile_fog

      此指令表示,编译出几个不同的Shader变体来处理不同类型的雾效(关闭/线性/指数/二阶指数)(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_fwdadd后的变体数量
使用上述代码忽略keywordk之后的变体数量

注:Unity中最多可以有256个全局关键字,但是Unity自己已经定义了一部分了(预留了大概60个左右内部使用),所以实际上会更少。所以使用multi_compile和shader_feature的时候,就需要特别注意不要超过这个限制。

番外.关于local keyword

      以下的内容在2019.1版本的文档中更新,所以2019之前版本是不支持local keyword的,我还傻傻的用我的2017.4试了一下。结果并不能生成keyword....

      为了解决keyword的问题,unity现在除了支持256个全局keyword以外,还支持64个local keyword。所以我们现在还可以使用shader_feature_localmulti_compile_local指令来生成local keyword满足我们的需求。使用local keyword有助于提高项目的性能,同时也可以减少每个shader中keyword数量。如果global keyword 与local keyword重名的话,unity会优先使用local keyword。

文档中对local keyword的解释
      但是同时,local keyword 与global keyword相比还有以下的几点限制:
1.不能将local keyword与global keyword更改的API一起使用(如Shader.EnableKeyword和CommandBuffer.EnableShaderKeyword)(可能指的是重名关键字?或者是不能用全局API来改变local keyword?)
2.每个shader最多只能使用64个local keyword
3.如果材质使用了一个local keyword并且启用了这个keyword,然后它的shder替换成了一个没有声明这个local keyword的shader,unity会声明一个global keyword

参考文章:
https://blog.csdn.net/poem_qianmo/article/details/49719247
https://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html
https://gameinstitute.qq.com/community/detail/121999

相关文章

网友评论

      本文标题:[Unity/shaderlab]关于着色器变体

      本文链接:https://www.haomeiwen.com/subject/ebvccctx.html