技术分享连载(四十四)

技术分享连载(四十四)

本期话题:脚本之间的依赖关系、Alpha通道分离、AssetBundle依赖和资源实例化...精选5个性能优化问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。

UWA QQ群:793972859


资源管理

Q1:我们在做依赖打包改进,比如UIAtlas这种脚本,AssetBundle包里脚本没有做依赖,每个包里都有这个脚本,会导致Mono堆内存增大么?对于“脚本也是资产”这一点理解的不是很透彻。脚本在AssetBundle里是不会启动,但是会出现脚本丢失。本身没有做依赖打包的话脚本是冗余在AssetBundle中吧?

首先,需要说明的是,脚本本身的内容是不会被打包到AssetBundle文件中的,AssetBundle文件储存的仅是脚本的索引信息。因此,即便有多个AssetBundle中都存在UIAtlas这一脚本索引,对堆内存也几乎是不产生影响的,且不会产生冗余问题。其次,脚本被当做资源且会产生依赖这一现象,仅在Unity 4.x版本中出现,而在Unity 5.0以后,脚本之间将不会产生依赖关系。因此,如果你目前还在使用Unity 4.x版本进行开发,那么依赖关系打包时确实需要注意这个问题,即依次Push A和B进行打包时,如果AssetBundle之间存在相同脚本,那么B会对A的脚本产生依赖。关于更为详细的分析,请查看我们之前的推送:揭秘AssetBundle 4.x


资源管理

Q2:我们正在权衡是否对纹理资源进行Alpha通道分离。现在发现,Android低端机上(OPENGL ES 2.0)使用Alpha分离,内存相当是两个ETC1的大小(相对RGBA32是小了很多),但是Shader中纹理采样会执行两次,这个采样其实对低端机消耗还是蛮大的吧?在iOS上分离是没有意义的,而且分离之后使用上会变麻烦,这样权衡之下,分离Alpha只是改善内存的话,优势看起来感觉不太明显,是否有更好的说法来说明分离的优势?

在Android平台上实施Alpha分离操作,是我们非常推荐的做法。如果项目中RGBA32、ARGB32格式的纹理较多,那么研发团队确实需要考虑尽可能将这些纹理转换成两张ETC1格式的问题。不仅内存占用可以降低为之前的1/4,同时加载效率上也会大幅提升。对于不同格式的纹理资源加载效率对比,可以查看我们之前的技术文章:加载模块深度解析之纹理篇。现在纹理的Alpha通道分离操作并不麻烦,网上已经有很多现成的代码可以使用,比如Unity一键图集生成工具。同时,分成两张ETC1纹理确实会增加一次纹理采样操作,但经过大量项目的真机实测,我们并未发现在运行时会出现性能波动。对于iOS平台来说,其PVRTC格式本身已经支持Alpha通道,所以RGBA32/ARGB32格式纹理直接转成PVRTC格式即可。但目前也有不少团队为了使Android和iOS版本开发统一,其在iOS版本上也将其Alpha通道拆开,变成两种PVRTC进行处理。这种做法会增大内存,但好处是开发环境可保持一致,因此研发团队可根据自身情况来考虑是否采用。


资源管理

Q3:如果有一个AssetBundle A内容全是UI用的图片,另外一个AssetBundle B是一个UI的Prefab,在加载UI B的时候我为了节约加载时间,自己手动加载一下AssetBundle A,但是我发现UI B的加载速度并没有加快。所以想请教一下,当从AssetBundle里把这个Prefab GameObject拿出来的时候,它的初始化过程中是从哪儿读这些图片?

这是研发团队平时遇到的较为常见的问题。首先说明一下,如果AssetBundle B和AssetBundle A产生依赖,那么在仅仅加载AssetBunde B中的Prefab B_prefab时,其本身开销仅为B_prefab的加载开销,对于AssetBundle A中的依赖资源并无影响。但是在实例化B_prefab时,Unity引擎会去检查AssetBundle A中的依赖资源是否已经被加载好,如果没有加载好,则先加载AssetBundle A中相关资源,然后再实例化B_prefab。这其实就是大家经常遇到的初次实例化一个技能、角色时出现卡顿的主要原因。因此,如果大家想加快B_prefab的实例化效率,那么对于其依赖关系AssetBundle A中的相关资源,可提前进行预加载,从而减少B_prefab实例化时的相关资源加载时间。


资源管理

Q4:求教Mesh导入后这里的uv3和uv4是怎么回事?有的模型只有uv和uv2,有的有四套。
请输入图片描述

如果在模型导入时就存在 uv2,uv3,uv4,那么这是因为在建模软件中添加了这些顶点属性。一般来说uv3和uv4的使用较为少见,通常是用来配合特殊的Shader实现特殊的效果。而uv2通常被用于Lightmap,uv2可以在建模软件中添加,也可以在Unity中通过Generate Lightmap UVs的选项来生成。


UI 输入

Q5: 在UWA上周六的分享会中,我收获了不少性能优化的知识点,同时也有个疑惑,是关于“UI Mesh重构”这个话题。当时UWA说“把一个UI界面移出屏幕或者缩放是不会引起UI Mesh的重构”,但是我今天测试了一下,在UISprite上面挂了一个脚本,让它移出相机屏幕或者手动更改坐标时,发现都会出现CPU峰值,看上去确实是Mesh重建造成的。下面是我的测试截图:
请输入图片描述
上图是NGUI的第一个Scene,里面就在父节点只有一个UIPanel,这是我的测试环境。
请输入图片描述
请输入图片描述
上面两张图是我的测试截图,主要包括移动Transform和缩放Transform数据等,从Profiler中看都有Mesh重建。因此,我的测试结论是:无论是移出屏幕还是缩放为0,以及Deactivate操作都会引起Mesh的重构。希望UWA可以再测试一下,给一个结论。

改变UI Transform(移出屏幕、Scale为0等)是需要以Panel为单位的,即不要移出单个Widget,而是将不再使用的UI界面(Panel)整体移出屏幕外。该朋友提供的测试例子没有问题,因为只用了一个UIPanel,且移动的是其中的Widget,所以造成了这个UIPanel的整体耗时。因此,建议尝试把需要移除的UI元素放在一个独立的UIPanel中,然后直接移动UIPanel,这样就不会有CPU峰值出现了。

关于隐藏UI的详细描述,可以参考我们之前的技术推送:NGUI性能优化技巧。下文是部分片段:
请输入图片描述
其中,值得研发团队注意就是第二点中的“以UIPanel为单位”,因为Mesh的拼合是以UIPanel为单位的,整体移动UIPanel不会重建或更新Mesh,但移动其中一部分元素则依然会更新Mesh的。


推荐活动

干货云集,实力撩你!UWA优化日深圳站即将起航,戳此报名!

请输入图片描述