-
製作圖集的好處:衆所周知CPU是用來處理遊戲的邏輯運算的,而GPU是用來處理遊戲中圖像的。在GPU中,我們要繪製一個圖像需要提交圖片(紋理)到顯存,然後再進行繪製(在這個過程中會產生一次DrawCall),也就是說我們要繪製100張圖片就要產生100次DrawCall.顯然這是非常消耗性能的。這是製作圖集的好處就顯而易見了:
-
①、減少性能消耗,提高處理效率
-
②、可以歸類不同模塊的圖片
-
③、一次加載或者卸載完成多圖片的處理,提高了運行效率
-
打包圖集需要的工具
我們經常聽說是在NGUI中打包圖集,在用UGUI時,我們也需要將一個個小圖打包成圖集,以減小Drawcall(類似coco2d-x一樣,打包成圖集一次性加載以內存換取圖片讀取效率),UGUI打包並使用圖集有兩種方法:
- 一種是使用系統自帶的打包工具SpritePacker;
- 一種是使用外部插件TexturePacker打包圖片並使用;
關於第一種方法有另一個文章爲大家講解,另一種熟悉的方法用TexturePacker工具打包,也是本文下面要講解的本文所使用的是Unity 2018.2.5f1 (64-bit)版本,TexturePacker 5.2.0版本最新版本
1,先用TexturePacker打小圖打包成我們所需要的圖集,打包的格式要注意是"Unity - Texture2D sprite sheet"(有一些低版本的TP是沒有這個格式的。具體使用方法可以瀏覽下面的網站https://www.codeandweb.com/texturepacker/documentation
2、打包之後會有一個.png和一個.tpsheet,不用作其他修改,將這兩個文件放在工程資源中,這時從工程看這只是一張大圖,並不能算是一個圖集,使用裏面的小圖(這時雖然可以用unity3d自帶功能,手動對圖片進行裁剪,但裁剪的小圖大小基本是不對的)
2,接下來需要下載並導入一個Unity3d的插件,TexturePacker自己出的的一個插件(TexturePacker Importer),插件鏈接https://www.assetstore.unity3d.com/en/#!/content/16641,下載併成功導入之後,不用寫任何代碼,作任何操作,插件會自己根據.tpsheet,將剛纔打包好放進入工程的大圖自動裁剪成小圖,如下圖,打圖集點開
我們只需像使用單獨小圖一樣,將圖集裏的小圖拖進Source Image裏即可。這時我們還只能在編輯器裏設置使用圖集。
3.我們還需要在程序中動態加載圖集並使用圖集裏的小圖,纔算是完整的。unity3d 並沒有明確api說明我們如何用這種圖集,而常用Resources.Load()加載只能返回單獨的一個圖片紋理,所以我們用另一個方法 Resources.LoadAll();加載整一張圖集,此方法會返回一個Object[],裏面包含了圖集的紋理 Texture2D和圖集下的全部Sprite,所以我們就可以根據object 的類型和名字找到我們需要的某張小圖片。
4.下面寫了一個圖集紋理的管理類,去統一管理加載,是一個單例類,找個不被銷燬的GameObject綁定就行, 代碼比較簡單,用一個Dictionary按圖集的路徑過key將加載過的圖集緩存起來,需要時再由外部刪除掉,下面是代碼:
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;
}
//圖集的集合
private Dictionary<string, Object[]> m_pAtlasDic;
private void Awake()
{
initData();
}
private void initData()
{
PPTextureManager.m_pMainObject = gameObject;
m_pAtlasDic = new Dictionary<string, Object[]>();
}
//加載圖集上的精靈
public Sprite LoadAtlasSprite(string _spriteAtlasPath,string _spriteName)
{
//從緩存中查找圖集
Sprite _sprite = FindSpriteFormBuffer(_spriteAtlasPath, _spriteName);
if(_sprite == null)
{
Debug.LogError("查找的圖集爲空");
Object[] _atlas = Resources.LoadAll(_spriteAtlasPath);//加載圖集
m_pAtlasDic.Add(_spriteAtlasPath, _atlas);//將加載的圖集存到字典中(路徑對應圖片)
_sprite = SpriteFormAtlas(_atlas, _spriteName);//從圖集中找到圖片
}
return _sprite;
}
//從圖集中找出sprite
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;
}
//從緩存中查找圖集並找出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;
}
//刪除圖集緩存
public void DeleteAtlas(string _spriteAtlasPath)
{
if(m_pAtlasDic.ContainsKey(_spriteAtlasPath))
{
m_pAtlasDic.Remove(_spriteAtlasPath);
}
}
}
接下來是如何使用:
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;
}
}
這樣就可以動態使用圖集中的圖片啦!!!