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

      在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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342