技术分享连载(五十四)

技术分享连载(五十四)

本期话题:UGUI 动态加载图片、AddComponent 堆内存分配、UI Layer 隐藏 ...精选5个性能优化问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。


UI 输入

Q1:UWA的直播里说的“将UI的Layer设置为不可见,从而将UI屏蔽”的方式具体是怎么实现的?为什么我在NGUI下直接设置UI元素的Layer不会生效呢?

在NGUI中使用修改Layer的方式隐藏界面,必须以UIPanel为单位,即直接修改UIPanel所在的GameObject的Layer才会生效。因为对于UISprite或者UILabel,都会在运行时被强制修改为与所在UIPanel保持一致。


资源管理

Q2:Unity里的Shader能不能用关键字#ifdef #endif把整个pass包起来?

#ifdef 和 #endif 并不能写在Pass之外,如果有动态开关Pass的需求,可以通过Shader Lod来实现,即设置两个Level不同的SubShader分别包含1个和2个Pass,直接通过改变该Shader的局部Lod值,即可实现SubShader的切换。关于Shader Lod的细节,可见官方文档:
http://docs.unity3d.com/Manual/SL-ShaderLOD.html


UI 输入

Q3:UGUI用Resource来动态加载图片,有什么好的方法? 我的理解是:Resource目录下的图片都不能被打包成图集,而且会增加DrawCall和包大小。

需要打图集的Sprite确实不建议放置在Resources下,如果需要动态加载,并且不希望使用AssetBundle,则可以尝试把需要动态加载的Sprite统一引用到Prefab上进行管理(类似于NGUI的管理方式,一个图集对应一个Prefab),然后动态加载Prefab并查找其管理的Sprite即可。另一种方式是,可以直接关闭Unity的Sprite Packer功能,通过第三方的工具来进行图集的打包,导入Unity时转为Multiple类型的Sprite资源,那么即使放在Resources文件夹下,也不会造成DrawCall无法合并的问题。


图形渲染

Q4:编辑器模式下,Prefab用Select Dependencies选项找依赖资源的时候,会把以前旧Shader引用的贴图也给关联上,怎么刷新这种引用关系?

在切换Material所使用的Shader时,其上的纹理引用确实是不会自动清除的(除非被覆盖)。因此,我们的建议是,在编辑Material时,如果要切换Shader,那么在切换好之后,进行一次Reset的操作(如下图所示,该操作会重置所有使用中的属性,同时去掉未使用的属性),然后再开始编辑其属性。
请输入图片描述
如果希望在不改变当前使用属性的前提下,去掉未使用的属性,那么据我们所知,只能启用Editor的Force Text模式,打开对应的.mat文件进行手动去除。


性能优化

Q5:请问怎么优化下图这两者的GC Alloc?每次AddComponent 都会有这么多的开销。

请输入图片描述

图中的两项GC Alloc是在进行AddComponent时不可避免的,因此只能通过尽量减少AddComponent的调用次数来进行优化。

今天的分享就到这里。也欢迎热爱进步的你加入UWA的QQ群(793972859),也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。 比起闭门造车,我们更乐意与大家各抒己见,畅所欲言;比起形而上的泛泛而谈,我们更乐意与大家直击痛点,对症下药。