UnityShaderVariant的一些探究心得

  最近遇到了一个问题,角色在Unity编辑器里运行渲染结果都是好的,打包到IOS上却发现,角色身上渲染的很黑.花了些时间查了查,又试了试,把这方面算是初步弄清楚了。

  先说出现问题的原因,由于我们把shader打包进了AssetBundle中,并且在Shader中使用了shader_feature来定义了宏。

  为了完整起见,先从unity的shader  variant说起。



ShaderVariant



  举个例子,对于一个支持法线贴图的Shader来说,用户肯定希望无论是否为Shader提供法线贴图这个Shader都能正确的进行渲染处理。一般有两种方法来保证这种需求:

  1.在底层shader(GLSL,HLSL等)定义一个由外部传进来的变量(如int),有没有提供法线贴图由外部来判断并给这个shader传参,若是有则传0,否则传1,在Shader用if对这个变量进行判断,然后在两个分支中进行对应的处理。

  2.对底层shader封装,如Unity的ShaderLab就是这种,然后在上层为用户提供定义宏的功能,并决定宏在被定义和未被定义下如何处理。最终编译时,根据上层的宏定义,根据不同的组合编译出多套底层shader.

  上述两种方法,各有利弊,对于前者由于引入了条件判断,会影响最终shader在GPU上的执行效率。而后者则会导致生成的shader源码(或二进制文件)变大。Unity采取的是后者,我们这里也只讨论Unity对后者的使用。

  Unity的Shader中通过multi_compile和shader_feature来定义宏(keyword)。最终编译的时候也是根据这些宏来编译成多种组合形式的Shader源码。其中每一种组合就是这个Uniy Shader的一个Variant。



MaterialShaderVariant的关系



  一个Material同一时刻只能对应它所使用的Shader的一个variant。进行切换的要使用Material.EnableKeyword()和Material.DisableKeyword()来开关对应的宏,然后Unity会根据你设定的组合来匹配响应的shader variant进行渲染。如果你是在编辑器非运行模式下进行的修改那么这些keyword的设置会被保存到材质的.mat文件中,尝试用NotePad++打开.mat文件,你应该会看到类似于下面的一段内容(需要在编辑器设置里把AssetSerializationMode设置为Force Text):

 1 %YAML 1.1
 2
 3 %TAG !u! tag:unity3d.com,2011:
 4
 5 --- !u!21 &2100000
 6
 7 Material:
 8
 9   serializedVersion: 6
10
11   m_ObjectHideFlags: 0
12
13   m_PrefabParentObject: {fileID: 0}
14
15   m_PrefabInternal: {fileID: 0}
16
17   m_Name: New Material
18
19   m_Shader: {fileID: 4800000, guid: 3e0be7fac8c0b7c4599935fa92c842a4, type: 3}
20
21   m_ShaderKeywords: _B
22
23   m_LightmapFlags: 1
24
25   m_CustomRenderQueue: -1
26
27   …

  其中的m_ShaderKeywords就保存了这个材质球使用了哪些宏(keyword).

  如果你手头有built-in Shader的源码可以打开里面的StandardShaderGUI.cs看一下Unity自己事怎么处理对于StandardShader的keyword设置的。

  另外Shader.EnableKeyword,和Shader.DisableKeyword是对Shader进行全局宏设置的,这里不提了。



multi_compileshader_feature的区别



  完全没接触过它们的同学可以先看官方文档的介绍,multi_compile是一直都有的,shader_feature是后来的unity版本中加入的。

举例介绍一下multi_compile和shader_feature:

1.如果你在shader中添加了

1 #pragma multi_compile  _A _B
2 #pragma multi_compile  _C _D

  那么无论这些宏是否真的被用到,你的shader都会被Unity编译成四个variant,分别包含了_A _C,_A _D, _B _C,_B _D四种keyword组合的代码

2.如果是

1 #pragma shader_feature _A _B
2 #pragma shader_feature _C _D

  那么你的shader只会保留生成被用到的keyword组合的variant,至于如何判定被用到了一会提到Assetbundle时候会说。



ShaderVariantAssetbundle的关系



  我所遇到的问题正是和Assetbundle(简称AB)有关,原因是打成AB包之后shader_feature所定义的宏没有被包含进去。

  上面说了multi_compile定义的keyword是一定能正确的生成对应的多种组合的shaderVariant,但shader_feature不尽然,Unity引入shader_feature就是为了避免multi_compile那种完整编译所导致的冗余的没有被使用的shader_variant被生成。shader_feature判断相应的keyword组合是否被使用。需要区分一下几种情况:

  1.如果shader没有与使用它的材质打在一个AB中,那么shader_feature的所有宏相关的代码都不会被包含进AB包中(有一种例外,就是当shader_feature _A这种形式的时候是可以的),这个shader最终被程序从AB包中拿出来使用也会是错误的(粉红色).

  2.把shader和使用它的材质放到一个AB包中,但是材质中没有保存任何的keyword信息(你再编辑器中也是这种情况),shader_feature会默认的把第一个keyword也就是上面的_A和_C(即每个shader_feature的第一个)作为你的选择。而不会把_A _D,_B _C,_B _D这三种组合的代码编译到AB包中。

  3.把shader和使用它的材质放到一个AB包中,并且材质保存了keyword信息(_A _C)为例,那么这个AB包就只包含_A _C的shaderVariant.

  可以看到shader_feature所定义的keyword产生的ShaderVariant并不是全部被打包到AB中,特别是你想在游戏运行时动态的通过EnableKeyWorld函数来进行动态修改材质使用的shaderVariant,如果一开始就没有把对于variant放进AB包,自然也就找不到。



ShaderVariantCollection



  要正确的让各种variant正确的在游戏运行时正确处理,

最直接暴力的两种方法:

1.把Shader放到在ProjectSetting->Graphics->Always Include Shaders列表里,Unity就会编译所有的组合变种。

2.把Shader放到Resources文件夹下,也会正确处理,我猜也应该是全部keyword组合都编译,有知道的同学,麻烦留言告诉我。

  但是这两种情况最大的问题就是组合爆炸的问题,如果keyword比较少还好,要是多了那真是不得了,比如你把standardShader放进去,由于它有大量的keyword,全部变种都生成的话大概有几百兆。另外一个问题就是这种办法没法热更新。自然不如放到AB包里的好控制。

  放到AB包就又涉及到shader_feature的处理,为了在运行时动态切换材质的shadervariant,可以在工程里新建一堆材质,然后把每个材质设置成一种想要的keyword组合,把他们和shader放到一起打到一个AB中去,这样虽然能让shadervariant正确生成,但是这些Material是完全多余的。

  为了解决这种问题,Unity5.0以后引入了ShaderVariantCollection(下面简称SVC),这里不讲用法,只说问题,这个SVC文件可以让我指定某个shader要编译都要编译带有哪些keyword的变种。并且在ProjectSetting->Graphics界面新加了一个Preloaded Shaders列表,可以让你把SVC文件放进去,编译时指定的Shader就会按照SVC中的设置进行正确的variant生成,而不会像Always Include Shaders列表中的那样全部变种都生成。

  但是它在AB中的表现可就不尽如人意了,要让它起作用,就必须把它和对应的shader放在一个AB中,而且除了5.6以外版本,我试了几个都不能正确使用,不是一个variant都没生成,就是只生成一个shadervariant(和放一个没有设置keyword的材质效果一样).你可以自己用UnityStudio打开查看一下生成的AB内容。



写在最后



  应该正确的理解Unity提供multi_compile和shader_feature以及ShaderVariantCollection的意图,根据自己的情况来选择合理的解决方案。

  在查这个问题的过程中也google了一些,发现国外在这方面的讨论远没国内多,应该是因为老外很少使用热更新这种东西,也自然很少用AB。

  

  尊重他人智慧成果,若要转载,请注明作者esfog,原文地址http://www.cnblogs.com/Esfog/p/Shader_Variant.html

时间: 2024-12-24 06:56:09

UnityShaderVariant的一些探究心得的相关文章

关于工作效率的心得分享

这是去年11月底在小组里分享过的工作效率心得,在这里也跟大家分享一下工作“快”感哈哈.我相信大家应该都有过工作效率的些许烦恼.而这个效率啊伴随我很长时间的痛苦.每每到PDI的时候领导必提效率有木有?自认为快是不算的,必须领导和客户方说了算,对于当年校招进来的毛驴,是一件泪崩漫长的提升过程.整天琢磨如何快,多快的速度才算快,恨不得快到连参照物都变得动感模糊.时间是把杀猪刀,不仅催人老还得与它赛跑,经过这几年的自残式磨练,也早该总结总结. 一. 懂得整理需求   效率是先把重要的事情优先排序来完成,

BaseAdapter中重写getview的心得以及发现convertView回收的机制

转载自:http://blog.csdn.net/pkxiuluo01/article/details/7380974 以前一直在用BaseAdapter,对于其中的getview方法的重写一直不太清楚.今天终于得以有空来探究它的详细机制. 下面先讲讲我遇到的几个问题: 一.View getview(int position, View convertview, ViewGroup parent )中的第二个参数是什么含义: 二.View的SetTag和getTag方法的用途: 先来解决第一个问

windows类书的学习心得(转载)

原文网址:http://www.blogjava.net/sound/archive/2008/08/21/40499.html 现在的计算机图书发展的可真快,很久没去书店,昨日去了一下,真是感叹万千,很多陌生的出版社,很多陌生的作者,很多陌生的译者,书名也是越来越夸张,什么××天精通××,精通××编程, ××宝典等等,书的印刷质量真的很好,纸张的质量也是今非昔比啊,但书的内容好象却是越来越让人失望,也许是我老了,我的思想我的观念已脱离现实社会,也许是外面的世界变化得太快,我编程数月,出去一走,

为什么报计算机还有阅读构建之法的心得

1.为什么选择计算机这个专业; 当初读本科的时候,一志愿填的是电气工程及其自动化,估计是因为分数太低了被调剂到了网络工程专业.之前的我并没有过多的接触计算机,感觉自己对这方面并没有多大的兴趣,本科的时候自己的学习并没有多么的认真.当时自己还想过要转专业,后来也不了了之了.慢慢的感觉这个专业还可以,也就学了三年,后来到了考研的时候,本来打算考金融专业的,但是跨专业考研难度挺大的,而且最近几年计算机这个专业实在是太火了,毕业之后工作找工作各方面都不错然后就限定决心考了计算机技术.庆幸的是考上了,现在

操作系统引导过程探究

操作系统引导探究 Version 0.02修改记录: 对与GDT有关的段描述符方面的描述进行了修订,更正了上一个版本中出现的一些错误,增加了一些描述,使其更完善. 与上个版本中不同的地方均用红色标记. 前言 本篇文章并不旨在完整的讨论一个多引导系统程序怎样去引导不同的操作系统,而只打算从编写操作系统的角度出发,谈谈计算机怎样从加电开始,从无到有,将操作系统运行起来,在其中将尽量详尽的描述从实模式到保护模式的过渡,目的只在于能将所学与广大爱好者共享,为希望开发操作系统的朋友留下一点资料,也为自己留

读书笔记:季羡林关于如何做研究学问的心得

以下的内容摘自: 季羡林 (2010-02-01). 牛棚杂忆(季羡林作品珍藏本)(图文版) (Kindle Locations 2701-2706).? . Kindle Edition. ? 我记得,鲁迅先生在一篇文章中讲了一个笑话:一个江湖郎中在市集上大声吆喝,叫卖治臭虫的妙方.有人出钱买了一个纸卷,层层用纸严密裹住.打开一看,妙方只有两个字:勤捉.你说它不对吗?不行,它是完全对的.但是说了等于不说.我的经验压缩成两个字是勤奋.再多说两句就是:争分夺秒,念念不忘.灵感这东西不能说没有,但是

iOS中的预编译指令的初步探究

看到非常好的两篇技术文,转来方便自己查看. 转自:http://www.cnblogs.com/daiweilai/p/4234336.html 开篇 我们人类创造东西的时候有个词叫做”仿生学“!人类创造什么东西都会模仿自己来创造,所以上帝没有长成树的样子而和人长得一样,科幻片里面外星人也像人一样有眼睛有鼻子……但是人类自己创造的东西如果太像自己,自己又会吓尿(恐怖谷效应),人类真是奇葩:奇葩的我们在20世纪创造了改变世界的东西——计算机(电脑),不用怀疑,这货当然也是仿生学!这货哪里长得像人了

关于工作效率的心得分享[转载]

来源:腾讯CDC 链接:http://cdc.tencent.com/?p=8182 这是去年11月底在小组里分享过的工作效率心得,在这里也跟大家分享一下工作“快”感哈哈.我相信大家应该都有过工作效率的些许烦恼.而这个效率啊伴随我很长时间的痛苦.每每到PDI的时候领导必提效率有木有?自认为快是不算的,必须领导和客户方说了算,对于当年校招进来的毛驴,是一件泪崩漫长的提升过程.整天琢磨如何快,多快的速度才算快,恨不得快到连参照物都变得动感模糊.时间是把杀猪刀,不仅催人老还得与它赛跑,经过这几年的自残

【iOS开发每日小笔记(二)】gitHub上的开源“瀑布流”使用心得

这篇文章是我的[iOS开发每日小笔记]系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧.该分类的文章,内容涉及的知识点可能是很简单的.或是用很短代码片段就能实现的,但在我看来它们可能会给用户体验.代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下(^_^).其实,90%的作用是帮助自己回顾.记忆.复习.如果看官觉得太easy,太碎片,则可以有两个选择:1,移步[iOS探究]分类,对那里的文章进行斧正:2,在