unity shader 变种(多重编译 multi_compile)

一、定义

在unity中我们可以通过使用#pragma multi_compile或#pragma shader_feature指令来为shader创建多个稍微有点区别的shader变体。这个Shader被称为宏着色器(mega shader)或者超着色器(uber shader)。实现原理:根据不同的情况,使用不同的预处理器指令,来多次编译Shader代码。
在运行时,Unity从Material宏Material.EnableKeyword和Shader.DisableKeyword或全局着色器宏Shader.EnableKeyword和Shader.DisableKeyword中选择适当的着色器变体。如果这两个宏都未启用,则Unity使用第一个宏。

二、使用

  1.  
    //定义两个TEST_1,TEST_2两个宏
  2.  
    #pragma multi_compile TEST_1 TEST_2
  3.  
    //在shader中使用
  4.  
    #ifdef TEST_1
  5.  
    //Todo
  6.  
    #endif
  7.  
    #ifdef TEST_2
  8.  
    //Todo
  9.  
    #endif

上面这个命令会产生2种着色器变种:TEST_1,TEST_2。
要生成未定义预处理器宏的着色器变体,请添加一个仅为下划线(__)的名称。这是避免使用两个宏的常用技术,因为对项目中可以使用的宏数量有限制,例如:

#pragma multi_compile __ TEST_1

在脚本中控制使用:

  1.  
    //使用TEST_1变种
  2.  
    Shader.EnableKeyword ( "TEST_1");
  3.  
    Shader.DisableKeyword ( "TEST_2");

三、组合

  1.  
    #pragma multi_compile TEST_1 TEST_2
  2.  
    #pragma multi_compile TEST_3 TEST_4 TEST_5

它产生总共六个着色器变体(TEST_1_TEST_3,TEST_1_TEST_4,TEST_1_TEST_5,TEST_2_TEST_3,TEST_2_TEST_4,TEST_2_TEST_5)。
所以如果有10行multi_compile,每行2个选项,那么将一共产生1024个着色器变体。
请记住,着色器变体数量将以这种方式疯狂增长。

四、pragma shader_feature

shader_feature非常相似multi_compile。唯一的区别是Unity shader_feature在最终版本中不包含未使用的着色器变体。所以shader_feature适用于在我们在编辑器中,选中材质,设置它使用的shader的宏,如果在程序中动态的去设置可能无效(原因下面说明)。而对于multi_compile,会把所有的变体都编译进程序里,所以适合需要在程序运行中动态改变状态的宏,适合全局设置 。
材质中设置位置截图:

五、宏限制

在unity中限制了全局的宏个数为265个,而unity内部使用了大约60个,所以在多个不同的着色器中定义全局宏时需要注意宏数量不要超过限制。
使用本地宏替代一部分全局宏:使用shader_feature_local和multi_compile_local。
shader_feature_local:类似于shader_feature,但枚举宏是本地的。
multi_compile_local:类似于multi_compile,但枚举宏是本地的。
在项目中除非是希望通过全局API启用的那些特定宏,否则应尽量使用本地宏,
使用更多本地宏和更少的全局宏,以减少每个着色器的宏总计数。如果存在具有相同名称的全局和本地宏,则Unity会优先使用local宏。
注意:
(1)不能将本地宏与进行全局宏更改的API一起使用(例如Shader.EnableKeyword或CommandBuffer.EnableShaderKeyword)。
(2)每个着色器最多有64个唯一的本地宏。
(3)如果Material启用了本地宏,并且其着色器更改为不再声明的宏,则Unity会创建一个新的全局宏。

六、内置multi_compile快捷方式

unity中提供一些内置的宏用于编译多个着色器变体。这些主要用于处理Unity中不同的光照,阴影和光照贴图类型。
multi_compile_fwdbase:编译PassType.ForwardBase所需的所有变体。变体处理不同的光照贴图类型,并启用或禁用主方向光的阴影。
multi_compile_fwdadd:为PassType.ForwardAdd编译变体。这将编译变体以处理Directional,Spot或Point Light类型及其变体与Cookie纹理。
multi_compile_fwdadd_fullshadows:同样multi_compile_fwdadd,但也包括灯具有实时阴影的能力。
multi_compile_fog:扩展为多个变体以处理不同的雾类型(off / linear / exp / exp2)。

大多数内置快捷方式都会产生许多着色器变体。如果您知道项目不需要它们,您可以使用#pragma skip_variants跳过编译它们中的一些。例如:

  1.  
    #pragma multi_compile_fwdadd
  2.  
    #pragma skip_variants POINT POINT_COOKIE

该指令跳过包含POINT或POINT_COOKIE的所有变体。

七、查看shader变种数量

  1.  
    #pragma multi_compile TEST_1 TEST_2 TEST_3
  2.  
    #pragma multi_compile TEST_4 TEST_5
  3.  
    #pragma multi_compile TEST_6 TEST_7

查看变体数量.png

 

上面的组合会产生3x2x2=12种变体,我们可以点击show查看具体的变体组合名称。

  1.  
    // Total snippets: 1
  2.  
    // -----------------------------------------
  3.  
    // Snippet #0 platforms ffffffff:
  4.  
    Keywords always included into build: TEST_1 TEST_2 TEST_3 TEST_4 TEST_5 TEST_6 TEST_7
  5.  
     
  6.  
    12 keyword variants used in scene:
  7.  
     
  8.  
    TEST_1 TEST_4 TEST_6
  9.  
    TEST_1 TEST_4 TEST_7
  10.  
    TEST_1 TEST_5 TEST_6
  11.  
    TEST_1 TEST_5 TEST_7
  12.  
    TEST_2 TEST_4 TEST_6
  13.  
    TEST_2 TEST_4 TEST_7
  14.  
    TEST_2 TEST_5 TEST_6
  15.  
    TEST_2 TEST_5 TEST_7
  16.  
    TEST_3 TEST_4 TEST_6
  17.  
    TEST_3 TEST_4 TEST_7
  18.  
    TEST_3 TEST_5 TEST_6
  19.  
    TEST_3 TEST_5 TEST_7

这里查看的是所有会被编译的变体的数量,也就是#pragma multi_compile声明的宏的全部组合。

  1.  
    #pragma multi_compile TEST_1 TEST_2 TEST_3
  2.  
    #pragma multi_compile TEST_4 TEST_5
  3.  
    #pragma shader_feature TEST_6 TEST_7

查看变种数量.png

  1.  
    // Total snippets: 1
  2.  
    // -----------------------------------------
  3.  
    // Snippet #0 platforms ffffffff:
  4.  
    Keywords stripped away when not used: TEST_6 TEST_7
  5.  
    Keywords always included into build: TEST_1 TEST_2 TEST_3 TEST_4 TEST_5
  6.  
     
  7.  
    6 keyword variants used in scene:
  8.  
     
  9.  
    TEST_1 TEST_4 TEST_6
  10.  
    TEST_1 TEST_5 TEST_6
  11.  
    TEST_2 TEST_4 TEST_6
  12.  
    TEST_2 TEST_5 TEST_6
  13.  
    TEST_3 TEST_4 TEST_6
  14.  
    TEST_3 TEST_5 TEST_6

上面的组合会产生3x2x1=6种变体,#pragma shader_feature没有特别处理的话只有会默认包括第一个宏。

八、编译

(1)material的ShaderKeywords

Material所包含的Shader Keywords表示启用shader中对应的宏,Unity会调用当前宏组合所对应的变体来为Material进行渲染。在Editor下,可以通过将material的inspector调成Debug模式来查看当前material定义的Keywords,也可在此模式下直接定义Keywords,用空格分隔Keyword。

 

设置ShaderKeywords.png

 

优点:根据material中的ShaderKeywords自动生成变体。无需额外设置
缺点:多个不同的material包中可能存在相同的shader变体,造成资源冗余。若在程序运行时动态改变material的keyword其变体可能并没有被生成
如上图设置:如果ShaderKeywords中没有设置TEST_6,这是如果我们想在程序中通过代码动态使用TEST_6这个宏(Shader.EnableKeyword("TEST_6"))。可能不能得到想要的效果,因为TEST_6这个变种没有生成。

(2)把Shader加入到Always Include Shaders列表里

找到ProjectSetting->Graphics->Always Include Shaders列表,将我们需要的shader添加到里面,这样unity将会把这个shader的所有的变种都生成出来。

 

AlwaysIncludeShaders.png

优点:我们不用担心项目发布出去以后有些变种没有生成,不能在程序中动态的去控制我们的宏。
缺点:生成的变体数量庞大,导致发布时间变长,游戏包体过大。比如你把standardShader放进去,由于它有大量的keyword,全部变种都生成的话大概有几百兆。

(3)使用ShaderVariantCollection是生成指定变体

ShaderVariantCollection是unity5.x以后用来记录shader的哪些变体需要被生成。这样做的好处就是在shader_feature与multi_compile结合使用时,能够设置生成何种变体,从而避免生成不必要的变体;shader不必和material打在一个包中,避免了多个包中存在相同的变体资源;明确直观的显示了哪些变体是需要生成的。

生成方式:

(1)通过Create->Shader-> Shader Variant Collection,就可以新建一个shader variant collection文件,手动添加需要编译的变种

 

ShaderVariantCollection.png

 

选择需要生成的变种.png

 

(2)通过Edit->Project Settings->Graphics中的save to asst...按钮,生成unity帮我们自动收集的,使用到的变种信息。

 

自动生成.png

这时候只需要先Clear一下,然后依次打开我们的所有场景,把需要的物体都显示一遍,Unity就会自动记录下来哪些着色器的哪些着色器变体已经被使用到。统计完后只需点击下面的保存按钮就可以生成我们所需要的ShaderVariantCollection资源。当然你也可以为你的每一个场景或者按需生成足够多的ShaderVariantCollection资源。自动收集的功能不一定百分百可靠,最好事后多检查。

ShaderVariantCollection加载:

启动时预加载:

 

最简单最粗暴的使用方式就是在游戏启动的瞬间就直接加载ShaderVariantCollection资源并编译里面的着色器变体,Unity已经为我们做好这一步了,依然还是在图形设置面板里,只需把需要启动是就编译的ShaderVariantCollection添加在Preloaded Shaders里面

预加载.png


代码加载:

由于ShaderVariantCollection也是一种资源,可以跟纹理、模型等等资源一起打包和加载等,只需在加载之后调用一句WarmUp。

  1.  
    ShaderVariantCollection shaderVariantCollection = Resources.Load <ShaderVariantCollection>( "MainShaderVariant");
  2.  
    if (shaderVariantCollection )
  3.  
    shaderVariantCollection.WarmUp ();

也可以把ShaderVariantCollection放在Resources目录下,好像会被自动加载。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据来源:中经数据库 主要指标110多个(全部都是纯粹的 市辖区 指标),大致是: GDP GDP增速 第一产业增加值占GDP比重 第二产业增加值占GDP比重 第三产业增加值占GDP比重 人均GDP 社会消费品零售总额 固定资产投资(不含农户) 新设外商投资企业数_外商直接投资 实际利用外资金额(美元) 一般公共预算收入 一般公共预算支出 一般公共预算支出_教育 一般公共预算支出_科学技术 金融机构人民币各项存款余额_个人储蓄存款 金融机构人民币各项存款余额 金融机构人民币各项贷款余额 规模以上工业企业单位数 规模以上工业企业单位数_内资企业 规模以上工业企业单位数_港澳台商投资企业 规模以上工业企业单位数_外商投资企业 规模以上工业总产值 规模以上工业总产值_内资企业 规模以上工业总产值_港澳台商投资企业 规模以上工业总产值_外商投资企业 规模以上工业企业流动资产合计 规模以上工业企业固定资产合计 规模以上工业企业利润总额 规模以上工业企业应交增值税 规模以上工业企业主营业务税金及附加 户籍人口数 年均户籍人口数 户籍人口自然增长率 第一产业就业人员占全部城镇单位就业人员比重 第二产业就业人员占全部城镇单位就业人员比重 第三产业就业人员占全部城镇单位就业人员比重 城镇非私营单位就业人员数 城镇非私营单位就业人员数_第一产业 城镇非私营单位就业人员数_第二产业 城镇非私营单位就业人员数_第三产业 城镇非私营单位就业人员数_农、林、牧、渔业 城镇非私营单位就业人员数_采矿业 城镇非私营单位就业人员数_制造业 城镇非私营单位就业人员数_电力、热力、燃气及水生产和供应业 城镇非私营单位就业人员数_建筑业 城镇非私营单位就业人员数_批发和零售业 城镇非私营单位就业人员数_交通运输、仓储和邮政业 城镇非私营单位就业人员数_住宿和餐饮业 城镇非私营单位就业人员数_信息传输、软件和信息技术服务业 城镇非私营单位就业人员数_金融业 城镇非私营单位就业人员数_房地产业 城镇非私营单位就业人员数_租赁和商务服务业 城镇非私营单位就业人员数_科学研究和技术服务业 城镇非私营单位就业人员数_水利、环境和公共设施管理业 城镇非私营单位就业人员数_居民服务、修理和其他服务业 城镇非私营单位就业人员数_教育 城镇非私营单位就业人员数_卫生和社会工作 城镇非私营单位就业人员数_文化、体育和娱乐业 城镇非私营单位就业人员数_公共管理、社会保障和社会组织 城镇非私营单位在岗职工平均人数 城镇就业人员数_私营企业和个体 城镇非私营单位在岗职工工资总额 城镇非私营单位在岗职工平均工资 城镇登记失业人员数 建成区面积 建设用地面积 建设用地面积_居住用地 液化石油气供气总量 液化石油气供气总量_居民家庭 人工煤气、天然气供气总量 人工煤气、天然气供气总量_居民家庭 液化石油气用气人口 人工煤气、天然气用气人口 城市公共汽电车运营车辆数 城市出租汽车运营车辆数 城市公共汽电车客运总量 道路面积 排水管道长度 建成区绿化覆盖面积 建成区绿化覆盖率 绿地面积 公园绿地面积 维护建设资金支出 土地面积 生活用水供水量 供水总量 全社会用电量 城乡居民生活用电量 工业生产用电量 房地产开发投资 房地产开发投资_住宅 限额以上批发和零售业法人单位数 限额以上批发和零售业商品销售总额 普通中学学校数 中等职业教育学校数 普通小学学校数 普通高等学校专任教师数 普通中学专任教师数 中等职业教育专任教师数 普通小学专任教师数 普通高等学校在校生数 普通中学在校生数 中等职业教育在校生数 普通小学在校生数 电视节目综合人口覆盖率 公共图书馆总藏量_图书 医疗卫生机构数_医院和卫生院 卫生人员数_执业(助理)医师 医疗卫生机构床位数_医院和卫生院 城镇职工基本养老保险参保人数 职工基本医疗保险参保人数 失业保险参保人数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值