Unity5 (5.0-5.2) Shader编译机制初探

来源:互联网 发布:tensorflow如何使用 编辑:程序博客网 时间:2024/06/08 15:01

被Unity坑了一把,简单说下吧,下面都是流水账,结论就写在最后了,就是Unity5 - 5.2的shader编译机制真是不咋地。

1.Why Always me?

问题是这样的,我照着Unity5 的Standard shader写了一个给我们工程用的简化版的标准Shader以及配合使用的ShadergGUI,里面融合了很多功能,包括支持法线啊、uv动画啊、半透镂空等等,通过shader_feature定义的宏将这些效果融合到一个shader里,这样既方便了美术,也方便了shader的管理,不用像原来一样工程里乱七八糟的一堆shader了。

不过后期在真机测试的时候遇到了一个问题,就是我通过EnableKeyword来动态修改材质表现在设备上不好使了。当时第一想法就是Shader中那么多条件宏在build的时候被Unity自动strip掉了,因为我们大部分的资源都打包成了Assetbundle包,工程实际只有一个空场景,Shader资源都放在了Resources目录下。如果说因为build的场景和资源里不包含shader的一些variant而被Unity自动去掉了这也是可以理解的。于是我就想GraphicsSettings里不是有个Always Included Shaders么,按照字面意思理解把shader放到那里去总是可以了吧,于是我就按下图设置了下。嘿!还真就好了! 
这里写图片描述

2.100MB WTF?

既然这样好了,那看来真机调试时其他的一些问题比如角色表现增强效果应该也是这个原因喽,那索性把其他的shader也都加进来吧,省的后面再出问题。别说这招真是包治百病,单机界面里我们还用了不少Standar shader,也就添加进来吧。ok,一切问题解决。。。。。。了吗? 
第二天测试就告诉我这个版本闪退频繁,一查都是内存爆了。拿Instrument一看我靠,一登录就快300MB了,看下Allocation,编译Shader居然就用了100多MB。难道说跟昨天把Standard Shader加进去导致的?虽然是很怀疑不过既然调试已经定位到这里还是试一下吧,于是乎把Standard shader从Always Included Shaders列表中移除再发布,嘿!还真就好了!

3.真相水落石出

现在的情况就是 
1.真机运行时Shader.EnableKeyword不好使,应该是因为Unity在Build时自动把没有用到的variant删减掉了(不是结论) 
2.通过Always Included Shaders设置解决了问题,不过导致内存大量增加,应该是因为Unity在启动时把该列表内的Shader的全部variant都展开编译了出来,所以一方面解决了上面的问题,一方面却增大了内存,而至于内存为什么会增加如此之多,那只能靠猜的了。 
既然这样,那就要想办法解决Shader的内存占用了,既然全部variant占据的空间太大就部分加载呗,正好Unity5增加了个ShaderVariantCollection这么个东西,看看好不好用。结果。。。。。多天的各种实验全部以失败告终,这包括: 
1.创建ShaderVariantCollection资源,包含目标shader的全部variant,并添加到GraphicsSettings的Preload Shaders列表中 
2.通过代码创建ShaderVariantCollection,并调用WarmUp接口

=========================流水账分割线==================================

下面总结下我分析出来的Unity5.0 - 5.2的Shader编译加载策略 
1. 发布工程时,Unity 会将全部multi_compile定义宏组合成的variant编译并加入包中 
2. 发布工程时,Unity 会将全部关联材质引用到的variant编译并加入包中 
3. 发布工程时,Unity会将Always Included Shaders列表中全部Shader的全部variant编译并加入包中 
4. Build Assetbundle时,Unity会将关联的Shader的全部由multi_compile定义的variant以及使用到的variant编译并加入包中

实测,使用multi_compile,是可以在运行时(真机上)用EnableKeyword和DisableKeyword动态改变材质,而shader_feature不行

文档中也写到:
So shader_feature makes most sense for keywords that will be set on the materials, while multi_compile for keywords that will be set from code globally.
shader_feature适合在材质中设置,而multi_compile 适合用代码全局设置

0 0