赞
踩
unity项目中使用精灵(Sprite)和其他图形来创建其场景的视觉效果。这意味着单个项目中可能包含许多纹理(texture) 文件。Unity 通常会为场景中的每个纹理发出一个绘制调用(DrawCall);但是,在具有许多纹理的项目中,过多的绘制调用会占用大量资源,并会对项目的性能产生负面影响。
为了降低性能消耗,我们可以使用精灵图集(Sprite Atlas)技术,它能够将多个纹理合并成一个大纹理,当访问图集中的多个纹理时,也只需要调用一次DrawCall。
关于Sprite Atlas 的使用可以参考–这里
在查找相关资料时由知乎文章:【Unity游戏开发】SpriteAtlas与AssetBundle最佳食用方案 得知不同的打包方案,即:
以下所有结论均在Unity 2021.3.11下得出
文件结构
两个AssetBundle包。
其中testImage使用了一个图集中的图元
A组:
勾选Include in build
打包散图文件夹,不打包SpriteAtlas
使用方式:
_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d");
img1.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1");
img2.sprite = _bundle2.LoadAsset<Sprite>("gameS-num2");
需要先加载atlas包,再使用prefab,否则build后 prefab无法正常显示纹理(editor下正常)
结论:
1. 使用两张散图,DrawCall仍记为1;
2. AB包中除了所有散图外,仍会有一张合并后的大图;
下图由AssetStudio分别读取AB包中的内容
testatlas.u3d:
testimage.u3d:
3. 改变图元调用的次数后
_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d");
img1.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1");
img2.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1");
img3.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1");
由MemoryProfiler检查内存可知,所有关于图元 "gameS-num1"的引用在内存中有且仅有一份,也就是说,以上方式加载的图元,以单例形式存在于内存之中,不同于C组结论3 . - B组: 不勾选Include in build
打包散图文件夹,不打包SpriteAtlas
使用方式:
_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d");
// img1.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1");
// img2.sprite = _bundle2.LoadAsset<Sprite>("gameS-num2");
结论:
无法加载图片,加载testatlas.u3d AB时调用 SpriteAtlasManager.atlasRequested ;
AB包中只有散图
加载prefab时不会调用 SpriteAtlasManager.atlasRequested (与D组差异)
prefab无法正常显示;
C组:
勾选Include in build
不打包散图文件夹,打包SpriteAtlas
使用方式:
_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d");
atlas = _bundle2.LoadAsset<SpriteAtlas>("testAtlas");
img1.sprite = atlas.GetSprite("gameS-num1");
img2.sprite = atlas.GetSprite("gameS-num2");
结论:
1. 使用SpriteAtlas,调用多个图元,DrawCall记为1
2. 由AssetStudio分别读取AB包中的内容
testatlas.u3d:
testimage.u3d:
由此可见,AB包中除了所有散图外,会有一张合并后的大图;但是,prefab中也出现一份相同的图元,打包冗余;
_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d");
atlas = _bundle2.LoadAsset<SpriteAtlas>("testAtlas");
img1.sprite = atlas.GetSprite("gameS-num1");
img2.sprite = atlas.GetSprite("gameS-num1");
img3.sprite = atlas.GetSprite("gameS-num1");
由MemoryProfiler检查内存可知,所有关于图元 “gameS-num1"的引用都会clone出独立的一份,相对比A组造成大量的内存开销。同时由于prefab中也有一张图元,在加载AB包时,多次载入同一份图元"gameS-num1”。
D组:
不勾选Include in build
不打包散图文件夹,打包SpriteAtlas
使用方式:
_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d");
atlas = _bundle2.LoadAsset<SpriteAtlas>("testAtlas");
img1.sprite = atlas.GetSprite("gameS-num1");
img2.sprite = atlas.GetSprite("gameS-num2");
结论:
prefab中出现一份散图,打包冗余;
AB包中除了所有散图外,仍会有一张合并后的大图;
加载prefab时调用 SpriteAtlasManager.atlasRequested ;
prefab无法正常显示
E组
勾选Include in build
将散图文件夹,SpriteAtlas打入同一个AB包中
F组
不勾选Include in build
将散图文件夹,SpriteAtlas打入同一个AB包中
打包方式 | 是否勾选Include in build | 纹理合并是否成功 | 是否冗余1 | 先加载图元是否需要后绑定2 | 先加载prefab是否需要后绑定2 | 内存中图元的唯一性atlas.GetSprite(“xxx”) | 内存中图元的唯一性_bundle2.LoadAsset(“gameS-num1”); |
---|---|---|---|---|---|---|---|
对文件夹打包 | 是 | 是 | 否 | 否 | 否 | 是 | 不可用 |
对文件夹打包(无意义) | 否 | 否 | 否 | 是 | 否 | 不可用 | 不可用 |
对spriteAtlas文件打包 | 是 | 是 | 是 | 否 | 否 | 不可用 | 否 |
对spriteAtlas文件打包 | 否 | 是 | 是 | 是 | 是 | 不可用 | 否 |
将文件夹和spriteAtlas打入同一个包 | 是 | 是 | 否 | 否 | 否 | 是 | 否 |
将文件夹和spriteAtlas打入同一个包 | 否 | 是 | 否 | 是 | 否 | 是 | 否 |
综上所诉,在使用SpriteAtlas时,根据不同的情况使用不同的打包方案。需要特备注重的是否冗余,是否需要精灵在内存唯一。
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.U2D; using UnityEngine.UI; public class AtlasTest : MonoBehaviour { public Image img0; public Image img1; public Image img2; public Image img3; private SpriteAtlas atlas; private AssetBundle _bundle; private GameObject _testImage; private AssetBundle _bundle2; // Start is called before the first frame update void Start() { SpriteAtlasManager.atlasRequested += OnCallBack_AtlasRequested; SpriteAtlasManager.atlasRegistered += OnCallBack_AtlasRegistered; } private void OnCallBack_AtlasRegistered(SpriteAtlas obj) { Debug.Log("atlasRegistered: " + obj.name); //img1.sprite = atlas.GetSprite("gameS-num1"); //img2.sprite = atlas.GetSprite("gameS-num2"); } private void OnCallBack_AtlasRequested(string arg1, Action<SpriteAtlas> arg2) { Debug.Log("无法在运行时找到图集资源:"+ arg1); //_bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d"); atlas = _bundle2.LoadAsset<SpriteAtlas>("testAtlas"); arg2.Invoke(atlas); } public void OnClick_Start() { _bundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testimage.u3d"); var testImage = _bundle.LoadAsset<GameObject>("testImage"); _testImage=GameObject.Instantiate(testImage, img1.transform.parent); } public void OnClick_Start2() { _bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d"); atlas = _bundle2.LoadAsset<SpriteAtlas>("testAtlas"); img1.sprite = atlas.GetSprite("gameS-num1"); img2.sprite = atlas.GetSprite("gameS-num1"); img3.sprite = atlas.GetSprite("gameS-num1"); } public void OnClick_Start3() { _bundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + @"\testatlas.u3d"); img1.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1"); img2.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1"); img3.sprite = _bundle2.LoadAsset<Sprite>("gameS-num1"); } public void OnClick_Unload() { //GameObject.Destroy(_testImage); //img1.sprite = null; //img2.sprite = null; _bundle?.Unload(true); _bundle2?.Unload(true); } // Update is called once per frame void Update() { } }
打包用
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; public class ExportAssetBundles : MonoBehaviour { [MenuItem("Example/Build Asset Bundles")] static void BuildABs() { // Put the bundles in a folder called "ABs" within the Assets folder. BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows); } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。