当前位置:   article > 正文

【Unity3D】关于unity中spriteAtlas的打包方案及使用时内存状态的多组对照实验_unity spriteatlas

unity spriteatlas

精灵图集(Sprite Atlas)简介

【Unity Manual】

unity项目中使用精灵(Sprite)和其他图形来创建其场景的视觉效果。这意味着单个项目中可能包含许多纹理(texture) 文件。Unity 通常会为场景中的每个纹理发出一个绘制调用(DrawCall);但是,在具有许多纹理的项目中,过多的绘制调用会占用大量资源,并会对项目的性能产生负面影响。

为了降低性能消耗,我们可以使用精灵图集(Sprite Atlas)技术,它能够将多个纹理合并成一个大纹理,当访问图集中的多个纹理时,也只需要调用一次DrawCall。

精灵图集的使用

关于Sprite Atlas 的使用可以参考–这里

在查找相关资料时由知乎文章:【Unity游戏开发】SpriteAtlas与AssetBundle最佳食用方案 得知不同的打包方案,即:

  • 对照组A&B,将散图文件夹作为一个AssetBundle包。
  • 对照组C&D,将Sprite Atlas文件作为一个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");
    
    • 1
    • 2
    • 3

    需要先加载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");
    
    • 1
    • 2
    • 3
    • 4

    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");
    
    • 1
    • 2
    • 3

    结论:
    无法加载图片,加载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
    • 2
    • 3
    • 4

    结论:
    1. 使用SpriteAtlas,调用多个图元,DrawCall记为1
    2. 由AssetStudio分别读取AB包中的内容
    testatlas.u3d:
    在这里插入图片描述
    testimage.u3d:
    在这里插入图片描述
    由此可见,AB包中除了所有散图外,会有一张合并后的大图;但是,prefab中也出现一份相同的图元,打包冗余

    1. 改变图元调用的次数后
        _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");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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");
    
    • 1
    • 2
    • 3
    • 4

    结论:
    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时,根据不同的情况使用不同的打包方案。需要特备注重的是否冗余,是否需要精灵在内存唯一。

  1. 正确的打包方式应该是将图集和图元文件打入同一个AB包,在包体大小不变的情况下,还能使用不同的加载图元方式。一举多得 。
  2. 当预制体使用某一个图集中的图元时,建议不勾选include in build ,此时可以根据prefab需要的纹理加载对应的图集包。
  3. 当图集仅作为动态加载某些图元时,建议勾选include in build

完整测试用代码

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()
    {
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

打包用

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()
    {
        
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

  1. 其他引用图集中图元的prefabAB包中是否有多的图元。 ↩︎

  2. 是否调用了SpriteAtlasManager.atlasRequested 和 atlasRegistered。 ↩︎ ↩︎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/595932
推荐阅读
相关标签
  

闽ICP备14008679号