Unity production Atlas

Keywords: Unity

1, Benefits of atlas production:
As we all know, CPU is used to process the logical operation of the game, while GPU is used to process the image in the game. In GPU, if we want to draw an image, we need to submit the image (texture) to display memory, and then draw it (in this process, a DrawCall will be generated), that is to say, if we want to draw 100 pictures, we need to generate 100 drawcalls. Obviously, this is very performance consuming. This is the benefit of atlas making

① , reduce performance consumption and improve processing efficiency
② , pictures of different modules can be classified
③ , loading or unloading multiple images at one time, improving the operation efficiency

2, Tools needed to package the atlas
We often hear that it is to package the atlas in NGUI. When using UGUI, we also need to package small graphs into atlas to reduce Drawcall (like coco2d-x, package into atlas for one-time loading in exchange for image reading efficiency). There are two ways to package and use the atlas in UGUI:

One is to use the system's own packaging tool sprite packer;
One is to use the external plug-in TexturePacker to package pictures and use them;

There is another article about the first method for you. Another familiar method is packaged with TexturePacker tool. The next part of this article is about unity 2018.2.5f1 (64 bit) and TexturePacker 5.2.0, the latest version

1. Use TexturePacker first

Pack small drawings into the atlas we need. Pay attention to the format of "Unity - Texture2D sprite sheet" (there are some lower versions of TP that do not have this format). For details, please visit the following website https://www.codeandweb.com/texturepacker/documentation

2. After packing, there will be a. png and a. tpsheet. There is no need to make other changes. Put these two files in the engineering resources. At this time, from the engineering point of view, this is only a large picture, not a atlas. Use the small picture in it (although you can use unity3d's own function to manually crop the picture, the size of the cropped small picture is basically wrong)

3. Next, you need to download and import a Unity3d plug-in, a plug-in from TexturePacker Importer), plug-in link https://www.assetstore.unity3d.com/en/#!/content/16641 After downloading and importing successfully, the plug-in will automatically cut the big drawing which has just been packed and put into the project into a small one according to.tpsheet without writing any code and doing any operation

We just need to drag the small graph in the atlas into the Source Image just like using a single small graph. At this time, we can only use the atlas in the editor.

4. We also need to dynamically load the atlas in the program and use the small graphs in the atlas to be complete. unity3d doesn't have a clear api for how we use this kind of atlas, but often Resources.Load() loading can only return a single image texture, so we use another method Resources.LoadAll(); load the whole atlas, and this method will return an object [], which contains the texture of the atlas Texture2D and all sprites in the atlas, so we can find a small picture we need according to the type and name of the object.

5. A management class of atlas texture is written below to manage and load uniformly. It is a single example class. Just find a GameObject that will not be destroyed and bind it. The code is relatively simple. Use a Dictionary to cache the loaded atlas by passing the key according to the path of the atlas, and then delete it from the outside when necessary. Here is the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class PPTextureManager : MonoBehaviour
{
    private static GameObject m_pMainObject;
    private static PPTextureManager m_pContainer = null;
 
    public static PPTextureManager getInstance()
    {
        if(m_pContainer == null)
        {
            m_pContainer = m_pMainObject.GetComponent<PPTextureManager>();
        }
        return m_pContainer;
    }
    //Collection of atlas
    private Dictionary<string, Object[]> m_pAtlasDic;
    private void Awake()
    {
        initData();
    }
    private void initData()
    {
        PPTextureManager.m_pMainObject = gameObject;
        m_pAtlasDic = new Dictionary<string, Object[]>();
    }
    //Load sprites on atlas
    public Sprite LoadAtlasSprite(string _spriteAtlasPath,string _spriteName)
    {
        //Find atlas from cache
        Sprite _sprite = FindSpriteFormBuffer(_spriteAtlasPath, _spriteName);
        if(_sprite == null)
        {
            Debug.LogError("The found atlas is empty");
            Object[] _atlas = Resources.LoadAll(_spriteAtlasPath);//Load Atlas
            m_pAtlasDic.Add(_spriteAtlasPath, _atlas);//Save the loaded atlas to the dictionary (the path corresponds to the picture)
            _sprite = SpriteFormAtlas(_atlas, _spriteName);//Find pictures from the gallery
        }
        return _sprite;
    }
    //Find sprite from the graph set
    private Sprite SpriteFormAtlas(Object[] _atlas,string _spriteName)
    {
        for(int i = 0;i<_atlas.Length;i++)
        {
            if(_atlas[i].GetType()==typeof(UnityEngine.Sprite))
            {
                if(_atlas[i].name == _spriteName)
                {
                    return (Sprite)_atlas[i];
                }
            }
        }
        return null;
    }
    //Find the atlas from the cache and find sprite
    private Sprite FindSpriteFormBuffer(string _spriteAtlasPath,string _spriteName)
    {
        if(m_pAtlasDic.ContainsKey(_spriteAtlasPath))
        {
            Object[] _atlas = m_pAtlasDic[_spriteAtlasPath];
            Sprite _sprite = SpriteFormAtlas(_atlas, _spriteName);
            return _sprite;
        }
        return null;
    }
    //Delete the atlas cache
    public void DeleteAtlas(string _spriteAtlasPath)
    {
        if(m_pAtlasDic.ContainsKey(_spriteAtlasPath))
        {
            m_pAtlasDic.Remove(_spriteAtlasPath);
        }
    }
}

Next, how to use:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class createTexture : PPTextureManager
{
    private Image image;
    private PPTextureManager ppTextureManage;
    public GameObject obj;
    // Use this for initialization
    void Start ()
    {
        obj = transform.Find("Image").gameObject;
        Sprite _sprite = PPTextureManager.getInstance().LoadAtlasSprite("Textures/common", "xiazai");
        image = obj.GetComponent<Image>();
        image.sprite = _sprite; 
    }
}

In this way, you can use the pictures in the atlas dynamically!!!

Original link: https://blog.csdn.net/weixin_43899724/article/details/105143806

Posted by Andy-H on Mon, 22 Jun 2020 00:33:01 -0700