大家好,我是阿赵。
图集功能,对于制作游戏的朋友应该是很熟悉的。它可以把多张散图合并在一张大图里面,在实际渲染的时候,可以极大的减少DrawCall数量。
Unity引擎对于UI图集打包有2种方式,分别是旧版本的Sprite Packer和新版本的Sprite Atlas。
一、新旧版本图集功能的介绍:

在Project Setting里面的Editor页,找到Sprite Packer,点开Mode,可以看得到有5个选项。
第一个选项是关闭,意思是2种图集都不使用。剩下的四个选项,下面介绍一下:
1、旧版本的Sprint Packer

前两个带着Legacy的,就是旧版本的Sprite Packer。Enabled for Builds的意思是只有打包AssetBundle或者打包安装包的时候生效。Always Enabled的意思是所有情况都生效,包括在编辑器状态下。
一般来说,使用的时候如果要在编辑器就看到图集的效果,就要选择Always。不过如果项目里面的图集图片非常多的情况下,每次打开编辑器首次运行或者当有图片修改的时候,Unity引擎都会重新生成图集,这个过程是非常慢的。所以有时候只是为了看功能,一般选择Enabled for Builds就可以。
当选择了Legacy的 Enabled for Builds或者Always之后,在图片的导入属性里面会多了Packing Tag项,这里可以输入图集名字,图集名字相同的所有图片将会生成在同一个图集里面。

如果想看看图集的最终合并效果,可以打开Window——2D——Sprite Packer

这里可以看到合并图集的效果:

由于这一篇主要不是介绍Sprite Packer,所以就不展开说明了。
2、 新版本的Sprite Atlas
回到刚才Project Setting的Editor页里面,在Mode里面最下面的两项,就是新版本SpriteAtlas的选项:

同样是有Enabled For Builds和Always Enabled两项,含义和上面的一样,一个是只有打包时生效,另一个是在所有情况都生效。
Sprite Atlas的用法和Sprite Packer区别挺大,下面看看具体是怎样使用。
1. 创建Sprite Atlas
在Project的文件里面,要先创建一个Sprite Atlas文件。鼠标右键——Create——Sprite Atlas。我的习惯一般是把需要打包在同一个图集里面的图片放在同一个文件夹,然后把Sprite Atlas文件也创建在同一个文件夹内,Sprite Atlas文件的文件名和文件夹名相同,所以这里的Sprite Atlas文件名就是文件名“icon”。这样比较容易管理。

创建出来Sprite Atlas文件之后,需要手动把该图集包含的图片拖动到Objects for Packing列表里面。然后点击一下Pack Preview按钮,就可以立刻看到当前图集里面的图片生成图集后的情况。

2. Master和Variant
Sprite Atlas有一个很特别的功能,就是允许生成图集的变体。
当我们生成一个图集的时候,它的Type是Master的,说明它是一个主图集:

然后Sprite Atlas允许我们创建这个图集的变体,然后调整图集的缩放。这样做的好处是,假如游戏本身需要高质量和低质量2套资源,那么可以通过图集变体,直接生成多一套低质量的图集来使用。
具体的操作是,再创建一个Sprite Atlas文件(我的命名习惯是在原图集的文件名后面加low字母,所以文件名会是iconlow),然后把Type选择成Variant,然后指定一个之前做好的图集作为Master Atlas。然后下面的Scale选项就是图集的缩放,比如我这里输入的是0.6,意思就是新生成的图集的大小将会是原来图集的0.6倍。

仔细观察下面生成的图集预览,会发现图集总大小从512x512变成了308x308

二、 Sprite Atlas的性能分析
1、渲染合并
当通过Sprite Atlas加载同一个图集里面的多张图片时(加载的代码下面会说),会发现Batches是不会增加的,因为它们多张图实际上是存在于同一张图集大图里面。

如果我既加载正常的Sprite Atlas的Master图集里面的图片,又加载Variant变体图集里面的图片,会发现两者是不能合并的:

左边这个图集,就是低质量的图片,可以看得出,左边的图片是会模糊一些。
2、内存占用
使用Profiler来采样一下内存,会发现实际上现在是有2张图集图片在内存里面,一张是512x512的,另外一张是308x308的。可以看出,低质量的那张图集,占用的内存同样也小一些。所以如果在游戏里面预先设置了高低不同的质量选项,那么在有需要的时候只加载低质量的图集,可以时游戏的运行时占用内存变低。

3、 内存回收
在回收内存的时候,如果对于实际的资源,我们一般会用Resources.UnloadAsset(object)来回收单个资源。对于Sprite Atals来说,我们应该怎样回收呢?
如果直接回收加载出来的Sprite本身,会报错UnloadAsset can only be used on assets;
如果回收从AssetBundle里面加载的SpriteAtlas对象,实际上内存是不会释放的。
有效的回收方式是:
1. Resources.UnloadUnusedAssets
在确保没有任何引用该图集的资源时,具体是指Sprite Atlas加载出来的Sprite,包括没有代码上的引用,也没有场景里面的物体使用时,执行Resources.UnloadUnusedAssets();可以释放掉内存里面已经生成的图集图片。
2. AssetBundle.Unload(true)
这是终极绝招了,所有通过AssetBundle加载出来的资源,使用这个终极绝招,不论是否有引用,都会释放。
三、Sprite Atlas打包AssetBundle
现在有2个Sprite Atlas,一个是Master的icon,另外一个Variant的iconlow。
1、高低质量分别打包
如果单独对这两个文件设置不同的AssetBundleName,分别打包出来,可以看到:
icon:

iconlow:

这种情况下,如果需要不同质量的图集,可以加载不同的AssetBundle,然后加载对应的SpriteAtlas。
2、只打包高质量
如果iconlow不设置AssetBundleName,只设置icon:

这个时候,会发现虽然只打包了高质量的图集,但低质量的图集的Texture也包含在里面。
不过这个时候,如果加载了这个AssetBundle,然后再想通过iconlow的名字加载里面的SpriteAtlas,是加载不了的。
所以这是一种浪费,AssetBundle的容量大了,但加载不到低质量的图集。
3、 把高低质量的图集打包在同一个AssetBundle
如果我把icon和iconlow这两个SpriteAtlas都设置成一样的AssetBundleName,然后打包AssetBundle,毫无疑问,这个AssetBundle里面会包含高质量和低质量两个图集的图片

这时候我通过这个AssetBundle加载iconlow的图集,是可以成功加载的。
所以,是把高低质量的图集分开打包AssetBundle,还是把它们都打包在同一个AssetBundle其实都是可以的,可以根据自己的加载策略来决定。如果分开打包,就可以单独修改低质量的图集单独更新。如果在一起打包,我觉得管理起来会比较方便,不存在漏了一个导致加载出错。我自己是比较倾向于把高低质量打包在同一个AssetBundle加载的。
其实如果把散图也设置和icon图集同一个AssetBundleName,打在同一个AssetBundle里面,由于已经包含了图集的大图,这些小图也不会真的重复打出去的。如果单纯是把图集加载来读取Sprite,散图是不需要设置AssetBundleName的,但如果是被其他预设引用着,图片本身如果不设置AssetBundleName只设置SpriteAtlas的AssetBundleName,那么预设是不会有这个图片的依赖的。
所以,为了统一处理,需要注意:为了预设的依赖,在设置AssetBundleName的时候,散图和SpriteAtlas一起设置同一个AssetBundleName。
四、SpriteAtlas的代码读取方式:
需要注意一点,在Editor设置里面,一定要把Mode设置成Always Enabled:

如果设置了Disabled或者是Enabled For Builds,不论是从外部AssetBundle加载,还是从编辑器类用AssetDatabase加载的SpriteAtlas对象,从SpriteAtlas对象里面加载出来的Sprite,将会出现Texture为空的情况,加载出来的内容将会是一片空白。
由于是基于SpriteAtlas 这个对象来加载Sprite,所以核心的代码是:
先通过各种方式获取SpriteAtlas对象
SpriteAtlas sa;
然后从SpriteAtlas对象里面获取Sprite
sa.GetSprite(spriteName);
1、 在Unity编辑器读取项目本地的Sprite:
在项目开发的过程中,不一定随时会打包AssetBundle,我们一般会希望直接放图片到项目里面,就能正常读取。所以需要一个编辑器加载图集的方法。
其实如果是在编辑器内,通过路径直接用AssetDatabase.LoadAssetAtPath也是可以加载到合并图集之前的图片的。不过那样就没有图集的效果。所以还是希望通过SpriteAtlas.GetSprite(spriteName)来加载。这里我设置了一个变量叫做“isLoadLowSprite”,这个变量可以通过全局设置,控制是否需要加载低质量的图集。所以在加载的过程中,就不需要再传参数了。

最低0.47元/天 解锁文章
629

被折叠的 条评论
为什么被折叠?



