技术分享连载(六十四)

技术分享连载(六十四)

我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。
UWA QQ群:465082844
UWA 问答社区:answer.uwa4d.com


资源管理

Q:Unity 5 的 Shader Variant Collection 功能是否推荐使用?我有以下3个疑点:
1)使用 Shader 变体之后,Shader 是否还能走资源更新?抑或 Shader 不推荐走资源更新?
2)Shader 变体和 Shader Always Include 的主要区别是什么?二者对内存和帧率影响如何?
3)在 Unity 5 较早的版本中,Shader 变体功能似乎有一些Bug,现在是否可靠?

经过测试,在较新的版本中(如Unity 5.5.3),将ShaderVariantCollection与Shader打包在相同的AssetBundle中后,其中会包含该Shader在ShaderVariantCollection中指定的Variant。因此:

1)使用 ShaderVariantCollection后依然可以进行资源更新(通过更新AssetBundle,来更新Shader的实现或者ShaderVariantCollection中包含的Variant)。

2)ShaderVariantCollection与Always Included Shaders的区别主要在于打包时所包含的Variant。Always Included Shaders中的Shader,其所有的Variant都会被包含,好处是,理论上不会出现Variant丢失的情况;坏处是,会导致更大的发布包以及额外的内存占用,而影响最大的是手动进行Warmup时的耗时以及ShaderLab的内存占用。因此一般来说,对于Variant特别多的Shader(如Standard Shader),并不推荐放入Always Included Shaders中。

3)目前即使是较新的版本,其可靠性我们也并不能确保,依然建议在使用前进行一些测试来验证。

此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/591418087640b5a822204e73
如您对该问题仍有疑问,可以转至社区进行进一步交流。


性能优化

Q2:请问为什么我项目渲染中Material.SetPassFast的开销这么高?这个该如何优化?
请输入图片描述

Material.SetPassFast是Unity引擎在渲染过程中Material的轮循切换开销,一般在Unity5.0~Unity5.3版本中出现。它的开销主要分为两种:

1) Shader.CreateGPUProgram峰值开销
这种情况主要出现在Shader第一次渲染时。在Unity5.0以后,引擎为了避免Shader加载时过高的CPU峰值出现,已经将Shader.Parse和Shader.CreateGPUProgram两种操作分开执行,前者在Shader加载时,后者在Shader第一次渲染时。下图则为一款项目运行时渲染时的Shader.CreateGPUProgram开销。
请输入图片描述

2) 渲染状态切换开销
这种情况是几乎每一帧都发生的,有渲染的地方就会有Material的切换。从问题图中可以看出,在运行的16000帧中,Material.SetPassFast一共被调用137万次。这里可以认为几乎全部是渲染时Material的切换操作。因此,该项较高的主要原因还是材质切换操作过多所致。所以,建议研发团队在报告中的详细材质页面查看是否有过多“冗余”的材质出现,如有则尽可能降低材质的使用冗余度。
请输入图片描述


动画

Q3:Animator会把所有状态的AnimationClip加载到内存,有什么好的办法可以动态加载?

1)Animator Controller结构不需要改变,但动画需要变化。比如随着人物等级或技能升级,同种的攻击动作随着变化等。该种需求可以通过AnimatorOverrideController来进行完成,即按需加载新的AnimationClip,然后替换AnimatorOverrideController中相应的AnimationClip即可。目前,Unity的AnimatorOverriderController不仅可以进行单个替换,同时也可以ApplyOverrides成组替换;

2)Animator Controller结构需要改变,类似于Animation老版本动画的AddClip功能。这种需求需要替换AnimatorController,研发团队可以在动态加载AnimationClip的同时,动态加载相应的Animator Controller,然后进行替换即可。

以上方法研发团队可根据自身实际情况而定。


动画

Q4:为什么Transform.设置Parent会触发Animator的初始化吗?Parent是等于null的。
请输入图片描述

把 Parent 设为null,相当于把这个 GameObject 变为根节点。如果在设置之前这个 GameObject 本身是激活状态,但其的父节点是未激活状态,那么设置之后,相当于把这个GameObject 激活。而激活GameObject 时就会触发 Animator.Initialize 等操作了。


资源管理

Q5:美术做粒子的时候,粒子与粒子之间共用资源的情况很多,例如某几个粒子共用一个Material,某几个粒子共用一个贴图等,应该如何组织AssetBundle?要是对应到最细的那个程度,凡是共用过的资源都单独打一个AssetBundle,好像又会很琐碎,假如不那么做,粒子与粒子之间的AssetBundle又会有冗余。这方面有什么好的建议?

AssetBundle打包没有标准的方式,单就粒子系统而言,因为其个体本身比较小,并且在项目中经常大量出现,所以并不建议将粒子系统逐个打包,而是建议根据其出现频率进行打包,比如将同一段时间、同一出现场景等的粒子系统打包在一起。同时,由于粒子系统的Shader基本上都是Unity内置Shader,因此,尽可能将Shader进行依赖打包。我们在UWA Day 2017上对于这种情况进行了详细说明,其Shader在中低端移动设备上的加载开销较高,需要研发团队特别关注。

今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站(answer.uwa4d.com)上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:465082844(仅限技术交流)