动态图集方案说明
为了降低 UGUI 的 Draw Call,常用的素材预先整合在一张大图集上。但随着资源的增加,有些资源很难再统计那些资源一起使用的频率,例如道具图标,这就导致图集有效使用率很低,这也增加了内存的压力。
我们引入动态图集处理这类问题:取消预先整合图集的做法,将使用到的素材动态的组成图集。为了降低运算时的布局运算压力,图集的布局是固定的,同尺寸或者相近尺寸的资源才能进入动态图集。
Warning
一般来说只允许同尺寸使用,相近尺寸可考虑让美术调整设计尺寸。
压缩格式
以下为 Android 实机的压缩格式数据
Type | B | KB | MB |
---|---|---|---|
RGBA32 2048x2048 | 16,882,073.6 | 16,486.4 | 16.1 |
ASTC Block 4*4 2048x2048 | 4194304.0 | 4096.0 | 4.0 |
ASTC Block 5*5 2048x2048 | 2726297.6 | 2662.4 | 2.6 |
ASTC Block 6*6 2048x2048 | 1887436.8 | 1843.2 | 1.8 |
ASTC Block 8*8 2048x2048 | 1048576.0 | 1024.0 | 1.0 |
ASTC Block 10*10 2048x2048 | 734003.2 | 716.8 | 0.7 |
ASTC Block 12*12 2048x2048 | 471142.4 | 460.1 | 0.4 |
ASTC Block 12*12 2048x2048 | 471142.4 | 460.1 | 0.4 |
综合选用 ASTC 6x6 block,动态图集要求散图和动态图集压缩格式一致。
Warning
- ASTC NxN 系列格式要求素材的尺寸能被 N 整除,以 ASTC 6x6 为例,长宽 104 的图标无法被 6 整除,需要至少处理成 108。
- Unity Editor 下,即使切换成 Android 平台,数据也和手机上的有出入。
布局方案
为了避免图集中相连素材的像素污染问题,需要预留图片空间至少 1px 即可。一般来说这种处理,可以直接在图集中控制小图的布局位置即可。但是实际上图集 Texture2D 在创建的时候自带颜色,可能是黑色、灰色或者黄色(总之不透明),就使得我们必须事先设置一遍整个Texture2D 的像素成透明。
但对一个 2048 长宽的 Texture2D 逐像素处理贴图是非常耗时的,为了避免第一次创建图集的耗时,我们选中方案B。提前将 1px 的像素间隙加在 UI 的源素材中,加入 Atlas 时就不再添加间隙了,使用时的使用区域内缩 1px 即可。
这里引出另一项需求,需要有工具支持增加图片的透明边界。
素材导入流程
素材导入到 Unity 经过两层处理
- 导图工具拓展尺寸
- 调整载入格式
以 ASTC 6x6 为例,把一张 104 的资源纳入动态图集,最近能被 6 整除的尺寸是 108。那么就要在四周各加上 2px 的空白像素。
调整项
使用
Unity 新增 DynamicImage.cs
专门用于动态图集,并管理其中的引用。需要显示 Image 的对象,用 DynamicImage
代替 Image
。代码上
-- 依旧需要获取 iconModule,iconPath,这是基本的素材信息。
local iconModule, iconPath = ResPathManager.GetPetIcon(self.petCfg.modelId)
-- 专用的加载动态图集接口
local sprite = self:LoadSpriteTPDynamic(iconModule, iconPath)
-- C# DynamicImage 端需要 key 用于管理引用
local key = DynamicAtlasManager.GetDynamicKey(iconModule)
-- DynamicImage 提供的接口设置 sprite。
self.view.imgPetIcon:SetNewSprite(sprite, key)
常见问题
使用了动态图集的素材超出布局边界。
Unity 中看到的就是 100 的素材是 98 的基础上加入 1px 组成的。如果 NativeSize 布局,其实内容的尺寸是不变的。然而在运行模式下,动态图集的素材会先扣掉 1px 边界,就导致了用 100 尺寸显示 98 尺寸的素材,造成放大的效果。
对于这种情况暂不处理,如果影响实在恶劣,就只能抛弃图片自带边界的做法。
图片未正常显示
请确认散图和动态图集格式是否一致