技术分享连载(十)

技术分享连载(十)

本期话题:SpritePacker大概的工作机制、如何使用NGUI Atlas Packer的工作流程、如何确定游戏真正的内存消耗、关于PSS和Profiler之间的数值关系、如何在移动设备上,对Bloom和全屏抗锯齿进行优化...


【技术小札】是UWA推出的技术交流栏目,我们会将开发团队中反馈的常见问题加以总结并梳理在此,以供大家参考。本期我们收集到几个关于内存和UGUI的问题,小编觉得非常系统,值得大家借鉴哦。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


UI输入

Q1:在使用NGUI时,我们通常会将很多小图打成一个大的图集,以优化内存和Draw Call。而在UGUI时代,UI所使用的Image必须是Sprite;Unity提供了SpritePacker。 它的工作流程和UGUI Atlas Paker有较大的差别。在Unity Asset中,我们压根看不到图集的存在。 问题是:
1. SpritePacker大概的工作机制是什么样的?

2. 如果Sprite没有打包成AssetBundle,直接在GameObject上引用,那么在Build时Unity会将分散的Sprite拼接在一起么?如果没有拼接,那SpritePacker是不是只会优化Draw Call,内存占用上和不用SpritePacker的分离图效果一样?

3. 如果将Sprite打成AssetBundle,AssetBundle中的资源是分散的Sprite吗?如果不是,不同的AssetBundle中引用了两张Sprite,这两张Sprite恰好用SpritePacker拼在了一起,是不是就会存在两份拼接的Sprite集?

4. 如果想使用NGUI Atlas Packer的工作流程,改如何去实现?

  1. 简单来说,UGUI和 NGUI 类似,但是更加自动化。只需要通过设定 Packing Tag 即可指定哪些 Sprite 放在同一个 Atlas 下。

  2. 可以通过 Edit -> Project Settings -> Editor -> Sprite Packer 的 Mode 来设置是否起效,何时起效(一种是进入 Play Mode 就生效,一种是 Build 时才生效)。所以只要不选 Disabled,Build 时就会把分散的 Sprite 拼起来。

  3. 可以认为 Sprite 就是一个壳子,实际上本身不包含纹理资源,所以打包的时候会把Atlas 打进去。如果不用依赖打包,那么分开打两个 Sprite 就意味各自的AssetBundle 里都会有一个 Atlas。

  4. 可以通过第三方工具(如 Texture Packer)制作 Atlas,导出 Sprite 信息(如,第 N 个 Sprite 的 Offset 和 Width,Height 等),然后在 Unity 中通过脚本将该 Atlas 转成一个 Multiple Mode 的 Sprite 纹理(即一张纹理上包含了多个 Sprite),同时禁用 Unity 的 Sprite Packer 即可。

两种做法各有利弊,建议分析一下两种做法对于自身项目的合适程度来进行选择。


内存管理

Q2:同样的App,安装在不同的机型上,使用同样的自动化脚本进行自动化测试,App的内存消耗(ADB Dumpsys Meminfo)在不同的机型上结果迥异,有些机型只有200MB多的内存消耗,有些机型高达600MB。我们已经分析过OpenGL ES 2.0和OpenGL ES 3.0对ETC2贴图解压的影响。200MB左右的机型有些是ES2.0,600MB消耗的机型有些是ES3.0的,并且多次测试可重现。请问你们如何分析这个问题?是否有标准来确定游戏真正的内存消耗?

Android系统的内存消耗是根据芯片、OS的不同而不同的。ADB反馈出来的PSS其实仅是本机当前该App线程的内存消耗,该值与其他机器的信息其实是没有任何可比性的。

Unity的项目,其内存我们建议主要还是通过Profiler来看其内存消耗。因为它表示的是引擎开辟和分配的真实物理内存。


内存管理

Q3:首先用户或者产品只关心整体消耗,并不会以Profiler为准,内存不足的崩溃也不会以Profiler正常而消失。其次,我们降低Profiler统计的消耗后,OS的消耗也会大大降低,甚至下降的更多。我们据此判断:这两个数字不一样,但应该是有联系的。我们想知道联系是什么?

可以这样理解,Profiler 中的数字表示 Unity 向系统索要的内存值,而系统则会根据当前的内存情况、内存管理策略来进行分配,不同的硬件采取的策略是不同的(比如是否保留缓存,何时换页,内存回收的频率等等)。

PSS 就是获取当前的系统内存分配信息,这并不代表 app 的真实内存需求。
另外,还关乎 PSS 获取算法的具体实现,比如有些硬件不把显存计算在内,有些会计算等等。

关于PSS和Profiler之间的数值关系,我们认为确实是存在联系的,但该联系在不同的硬件上是不同的,且需要由硬件厂商来提供,这也是我们仅仅把 PSS 作为参考,把 Profiler 作为关注点的原因所在。


图形渲染

Q4:当关闭预渲染GI时会出现IndirectResolution,这个参数有什么用,为什么调大了以后会大大增加渲染时间,但是烘培出来没有啥效果。

简单来说,该值主要控制的是GI的烘焙密度,数值越大,表示每个单位距离内的texel越多,即烘焙得越精致,自然烘焙的时间也越长。该值并不需要越大越好,场景越小,建议该值越低。该值为1时,对于多数场景,其烘焙效果已经足够了,升高该值,其效果也不会有明显提升。

开发者也可以参考Unity官方的说明文档:
http://docs.unity3d.com/Manual/GlobalIllumination.html


运行性能

Q5:如何在移动设备上,对Bloom和全屏抗锯齿进行优化?Unity标准资源里面自带的效率比较低(已经尝试过Bloom(Optimized))。

建议使用Asset Store上适合移动端的Bloom Shader插件,比如FxPro: Bloom&DOF和BloomPro等。

对于AA,目前在移动设备上并没有特别优化的方法,仅能建议在低端设备上关闭AA功能,而在高端设备上可尝试开启较低倍数(2x)的MSAA。