Unity引擎的SpriteAtlas图集功能使用介绍

  大家好,我是阿赵。
  图集功能,对于制作游戏的朋友应该是很熟悉的。它可以把多张散图合并在一张大图里面,在实际渲染的时候,可以极大的减少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”,这个变量可以通过全局设置,控制是否需要加载低质量的图集。所以在加载的过程中,就不需要再传参数了。

Unity使用脚本创建SpriteAtlas,可以通过继承`EditorWindow`类并使用Unity Editor API来实现。以下是一个详细的实现方法,包括创建SpriteAtlas、设置打包参数以及保存生成的SpriteAtlas文件[^1]。 ### 创建SpriteAtlas的脚本 ```csharp using UnityEngine; using UnityEngine.U2D; using UnityEditor; using UnityEditor.U2D; using System.IO; public class GenerateScript : EditorWindow { [MenuItem("EditorTools/GenerateSpriteAtlas")] public static void ShowCustomEditorWindow() { // 创建SpriteAtlas保存的目录 string directoryPath = Application.dataPath + "/SpriteAtlas"; if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); // 创建一个新的SpriteAtlas实例 SpriteAtlas spriteAtlas = new SpriteAtlas(); // 设置SpriteAtlas的打包参数 SpriteAtlasPackingSettings packSetting = new SpriteAtlasPackingSettings() { blockOffset = 1, enableRotation = false, enableTightPacking = false, padding = 4, }; spriteAtlas.SetPackingSettings(packSetting); // 保存SpriteAtlas到指定路径 string localPath = directoryPath + "/SpriteAtlasName.spriteatlas"; AssetDatabase.CreateAsset(spriteAtlas, localPath); AssetDatabase.Refresh(); } } ``` ### 功能说明 - **目录创建**:在`Assets`目录下创建一个名为`SpriteAtlas`的文件夹,用于存放生成的SpriteAtlas文件。 - **SpriteAtlas实例**:通过`new SpriteAtlas()`创建一个新的SpriteAtlas对象。 - **打包参数设置**:通过`SpriteAtlasPackingSettings`类设置打包参数,如`padding`(精灵之间的间距)、`enableRotation`(是否允许旋转)等。 - **保存文件**:使用`AssetDatabase.CreateAsset`方法将SpriteAtlas保存为一个`.spriteatlas`文件,并调用`AssetDatabase.Refresh()`刷新资源数据库,确保新文件立即生效。 ### 获取SpriteAtlas中的Sprite 如果需要从已有的SpriteAtlas中获取所有Sprite,并将其转换为`Texture2D`对象,可以使用以下代码[^2]: ```csharp window.sprites = new Sprite[window.spriteAtlas.spriteCount]; window.spriteAtlas.GetSprites(window.sprites); window.texture2Ds = new Texture2D[window.sprites.Length]; for (int i = 0; i < window.sprites.Length; i++) { window.texture2Ds[i] = window.sprites[i].texture; } ``` 这段代码首先获取SpriteAtlas中所有的Sprite,然后遍历这些Sprite,提取它们的纹理并存储到`Texture2D`数组中。这在需要对Sprite的纹理进行进一步处理时非常有用[^2]。 ### 复制Sprite的纹理并重新创建Sprite 如果需要复制一个Sprite的纹理并重新创建一个新的Sprite,可以使用以下方法[^3]: ```csharp nowSpriteRenderer1 = nowTrans1.GetComponent<SpriteRenderer>(); Sprite sp = nowSpriteRenderer1.sprite; Texture2D txt = CDrawTexture.CopyTextureFrom(sp); sp = Sprite.Create(txt, new Rect(0, 0, txt.width, txt.height), new Vector2(0.5f, 0.5f)); // nowSpriteRenderer1.sprite = sp; ``` 这段代码通过`Sprite.Create`方法创建了一个新的Sprite,使用复制的纹理和指定的矩形区域及中心点位置。这在需要动态修改Sprite内容时非常有用[^3]。 ### 总结 通过上述代码和方法,可以在Unity使用脚本创建、管理和操作SpriteAtlas。这不仅有助于自动化资源管理流程,还能提高开发效率,特别是在需要批量处理Sprite资源的情况下。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值