Unity Shader AssetBundle ShaderVariantCollection 自己使用

(1)

1. 必定生成首个宏定义开启所对应的变体。

  Shader中通过#pragma shader_feature A定义了宏A,并在collection中加入了宏A所对应的变体,如图4所示:

 


图4

  此时生成的变体除了collection中已经存在的ForwardBase A外,还会生成变体ForwardBase nokeyword。因为只定义单个宏时,A 为 _ A的简写。实际上首个被定义的宏为nokeyword,故 nokeyword所对应的变体必定会被生成。

  同理,以 #pragma shader_feature A B C来定义宏时,即使collection中未添加变体Forward A,这个变体也必定会被生成(当shader的PassType仅有ForwardBase)。

2.Shader中有多个Pass时变体的生成规则

  a.读取ShaderVariantCollection中已存在的变体,获取它们的Keywords。

  b. 将这些Keywords分别与每个Pass的多组Keywords列表求交集,取交集中Keywords数量最多得那组。

  c. 用得到的Keywords与对应的PassType生成ShaderVariant,并添加到ShaderVariantCollection中。

  d. 若得到得交集中有新的Keywords,则回到b。 上述过程类似递归。例如: Shader 中有 ForwardBase、ForwardAdd、Normal 三种PassType(以下为了方便简称Base、Add、 Normal)。定义的宏如下:

BaseAddNormal#pragma shader_feature A

#pragma shader_feature B

#pragma shader_feature C#pragma shader_feature A

#pragma shader_feature E#pragma shader_feature A

#pragma shader_feature B

#pragma shader_feature E

  此时若ShaderVariantCollection中包含的变体是 Base ABC,Add AE。则此时生成的变体为:这三种PassType的默认定义的宏(nokeyword)所对应的变体(3个)以及原先直接包含的Base ABC、Add AE。除此之外Unity还会额外生成Add A、Base A、Normal A、Normal AB、 Base AB、Normal AE这6个变体。

ABC ∩ Add AE -> Add A (A is NewKeyword)
  A ∩ Base ABC -> Base A
  A ∩ Normal ABE -> Normal A
ABC ∩ Normal ABE -> Normal AB (AB is NewKeyword)
 AB ∩ Base ABC -> Base AB
 AE ∩ Normal ABE -> Normal AE

变体的调用规则

  当collection将变体准确生成后,便能在运行时通过修改material中的keywords来实现对不同变体的调用。

  假设某collection生成的变体只有Forward ABC,Forward ABE,Forward nokeyword这三种,则此时调用关系如下:

Material中的Keywords调用的变体解释A B CForward A B C正常匹配A BForward nokeyword没有匹配的变体,调用首个被定义的宏 所对应的变体A B C DForward A B C调用交集中keyword数量多的变体

ABCD ∩ ABC = ABC

ABCD ∩ ABE = ABA B C EForward A B C交集中keyword数量相同,在collection中谁在前就调用谁A B E CForward A B C与在material中的定义顺序无关

 


图5
以上均为根据测试结果总结归纳出来的规则,若有错误之处还请严加指正!

shader_feature方案项目具体实现方式

项目中变体的添加

  那么项目中是如何确定哪些变体是需要加到collection中的呢?我们的做法是:

  a. 遍历每一个Material,提取其shader keywords。

  b. 将获得的keywords与shader的每个PassType所包含的宏定义做交集,并将其结果添加到collection中。

  举个简单的例子:

  Material中的Keywords为A B C D,则shader的PassType、PassType中所定义的宏、需要往collection中添加的变体则如下表所示:

PassType定义的宏需要往collection中添加的变体ForwardBase#pragma shader_feature A

#pragma shader_feature BForward A B

(ABCD ∩ AB = AB)ForwardAdd#pragma shader_feature _ C DAdd C

(ABCD ∩ C = C,ABCD ∩ D = D,但C的定义在D前,故只添加C)Normal#pragma shader_feature _ E FNormal NoKeyword

(ABCD ∩ E = NoKeyword)

(ABCD ∩ F = NoKeyword)

  需要说明的是,我们自己的代码里为了降低变体生成逻辑的复杂度、保持collection面板上变体的直观性,不将Unity为我们额外生成的那几个变体添加到collection面板中,但要记得Unity是会为我们生成额外的变体的。

Shader变体收集与打包

https://zhuanlan.zhihu.com/p/68888831

(1)
自己收集 Shader 所有开启的关键字,在 ShaderVariantCollection 中开启,Shder 、 ShaderVariantCollection 必须打包到一个 AssetBundle ,材质可以不用打包到一起
参考
对Shader Variant的研究(概念介绍、生成方式、打包策略)
https://blog.csdn.net/RandomXM/article/details/88642534

Shader变体收集与打包
https://zhuanlan.zhihu.com/p/68888831

Unity3D Shader加载时机和预编译
https://www.cnblogs.com/rexzhao/p/7884905.html

(2)
仅仅添加 Shader 到对应的 ShaderVariantCollection 中,但是材质 、 Shader 和 ShaderVariantCollection 必须打包到一个 AssetBundle 中
参考
ShaderVariantCollection解决shader_feature丢失
https://www.dazhuanlan.com/2019/12/16/5df6a886cf4dd/

(3)
warmup 就是一次性创建 Gpu Program ,否则在使用的时候 Unity 才会自动创建 Gpu Program
ShaderLab在相关shader加入内存时就已经产生,但如果没有被渲染的话不会触发CreateGPUProgram操作,如果提前在ShaderVariantCollection中收集了相关变体并执行了warmup的话,第一次渲染时就不会再CreateGPUProgram,对卡顿会有一定好处。
参考文章:
Shader变体收集与打包
https://zhuanlan.zhihu.com/p/68888831

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值