【求知探新】Unity中ShaderLab内存优化

【求知探新】Unity中ShaderLab内存优化

【求知探新】是UWA新推出的栏目。在大家做性能优化的过程中,常常会遇到一些未知的问题,在这里我们将分享研究这些问题的完整过程。当然需要说明的是,一个好的问题没有标准的答案,在此也欢迎大家来积极拍砖!

这是侑虎科技第295篇原创文章,感谢作者LawLiet供稿,欢迎转发分享,未经作者授权请勿转载。
作者知乎:https://zhuanlan.zhihu.com/p/27336202


想必很多研发者都会对ShaderLab内存的优化头疼不已,在寸土寸金的内存中,它常常占据了不容忽视的体量,而比起其他资源内存,它更像一个“黑盒”,让我们优化的时候难以入手。为此,我们通过一些实验来剖析了ShaderLab的占用,以及如何优化这部分内存。


一、问题描述

请输入图片描述
从上图(进入战斗场景时的内存快照)可以看出,ShaderLab占用居然达到42MB,为什么Shader的占用那么高呢?


二、问题分析

请输入图片描述
由于当前项(ShaderLab)没有说明详细的Shader占用信息。所以只能去另外找原因了,还好,在内存快照的Assets下的Shader项中,有详细的使用信息。

然后我们看到Standard的Shader使用,但项目里面根本没有地方使用过Standard这个Shader,为什么会存在呢?

为此,我们进行了一轮的排查,把部分使用到Standard的地方清除掉,测试并再拿一次内存快照。
请输入图片描述
清除了一部分后,ShaderLab降到27.6 MB(后来完全清除掉Standard,降到21 MB)。果然,主要原因就出在了Standard上。那么问题又来了,为什么我们没有使用到Standard,却会在内存中看到Standard的使用呢?
这里就要说下两个坑了,同样,也是排查这个问题的方法。


三、问题排查

1、模型导入导致

模型导入的时候,“Import Materials”是默认勾选的。所以当模型导入时,Unity会在同目录创建“Materials”目录,并创建相应的材质,而这个材质默认是使用Standard。

由于美术在制作过程中对Prefab中对模型另外赋予材质,所以实际上,默认创建的材质(Standard)是没有使用到的。可是当加载模型的时候,却又把默认创建的材质加载上了,并对着色器解析了,因此导致内存中有Standard。

那么解决方法也很简单,把“Import Materials”去掉,并把没有使用的默认材质删除。

请输入图片描述

注意:如果不把“Import Materials”去掉,导入到其他项目时,材质又会自动创建了。

补充:
由于实际项目中,Prefab改动次数比较大,相应的模型文件改动比较少,所以把项目中的模型和对应的Prefab分开打包成不同的AssetBundle,然后就会出现一个很奇怪的情况。

没有勾选“Import Materials”的模型文件,在实例化Prefab时,ShaderLab会存在一份“Standard”的Shader内存,而这个Shader的引用是指向一个“Default-Material”文件(可是这文件并不存在)。
请输入图片描述
但是,在模型和Prefab在相同的AssetBundle中,或者使用Resources加载时,却不会有“Standard”和“Default-Material”的出现。暂时还不确定是否是Unity 5.3.3版本的Bug,还是Unity的特殊机制。

相关问题参考:https://answer.uwa4d.com/question/595377a5d516f3253948b0d1

临时解决方案:在需要模型与Prefab分开打包时,勾选“Import Materials”,直接使用和修改默认生成的材质。

2、默认模型(Cube、Sphere)创建导致
早期场景搭建时,为了方便定位和可视化,曾经使用Cube等系统默认的Mesh作为锚点,然后在启动游戏时禁用掉。由于这些Cube不启用,性能消耗很轻微,所以就没有理会了。

可是,就因为是系统默认的Mesh,所以创建时,赋予的材质就是默认的材质“Default-Material”,而这个材质使用的着色器就恰恰是“Standard”。所以“Standard”存在的并不冤了。
请输入图片描述

解决的方案也很简单,删掉这些Mesh或者是替换材质。这样,这部分占用的“Standard”就不存在了。


四、总结

由于Standard的变体太多了,所以当引用了Standard的时候,往往会存在多个Standard变体,占用大量的内存。如果,你发觉你的ShaderLab的内存过大,而又那么也不妨找找是不是上述的原因。

那ShaderLab占用内存过大是不是完全是Standard的原因呢?其实并不止的。像我们优化完之后的27MB(完全清除后是21MB),肯定还有其他原因造成的。可是,优化的过程是砍大头,像上文那样,稍微优化一下,就能拿掉20多MB,当然要立刻做,可是越往小的时候,优化效率就越来越低了,所以这时候就需要转移目标看一下“Assets”“Texture2D”这些大头了。所以,剩下ShaderLab的优化方向可能会在以后遇到的时候再补充。

PS:以上内容均在真机上测试


文末,再次感谢Lawliet将这篇极具参考价值的技术文章进行分享。同时,我们也欢迎大家在UWA问答社区(answer.uwa4d.com)积极提交研发过程中遇到的问题。也许随着时间的流逝,科技的进步,答案将变得廉价,但问题会变得更有价值,因为提问和研究将比回答更有力量。

  • Techniques for Game Development 25 发表在 3月25日 回复

    [...]Finally, when using the Standard Shader, you should not only pay attention to performance, but also pay attention to its impact on memory. You can refer to this article: 【Seeking new knowledge 】Shader[...]

  • hhy 发表在 2017年09月08日 回复

    你们怎么20多MB,什么版本的unity 我们项目5.3 shaderlab只有0.8mb