Unity UGUI图集专题
一:圖集介紹
什么是圖集:我們可以將其理解為將一系列小圖合并為一張大圖。使用圖集可以減少drawcall,提升效率。 ? 游戲中的圖片模型最終是要給到顯卡去渲染的,然后CPU通知GPU要開(kāi)始渲染,這一次通知就是一次Drawcall。當(dāng)一個(gè)UI里面圖片非常多的時(shí)候,我們可以使用圖集技術(shù)將其一次性渲染。
Unity打包圖集的方式有很多種,這里我們講解三種:
(1)一種是使用系統(tǒng)自帶的打包工具SpritePacker;
(2)使用SpriteAtlas進(jìn)行打包圖集
(3)使用TexturePacker打包圖片并使用;
?
二:SpritePacker使用
1、將所需要的圖片導(dǎo)入U(xiǎn)nity中,注意不能放在Resources文件夾下(圖片將不能被打包成圖集);
?
2、選擇需要打包成圖集的圖片(可以多選)在inspector面板里選擇“Texture Type“為“Sprite (2D and UI)”,并Apply應(yīng)用;
?
3、在”P(pán)acking Tag”選項(xiàng)里面填上圖集的名稱,該選項(xiàng)相同的圖片會(huì)打包為同一個(gè)圖集;
4、選擇菜單欄里面的 "Edit" -> "Project Settings" -> "Editor"; 5、在inspector面板里設(shè)置“Sprite Packers”下面的“Mode”選項(xiàng),其中,“Disabled”表示關(guān)閉圖集功能,“Enabled for Builds”表示打包發(fā)布時(shí)才打包圖集,“Always Enable”表示始終打包圖集;Enabled for Builds(Legacy Sprite Packer)表示打包發(fā)布時(shí)才打包圖集(使用舊版技術(shù));“Always Enable(Legacy Sprite Packer)”表示始終打包圖集(使用舊版技術(shù))
?
6、設(shè)置完上述選項(xiàng)后,選中需要打包圖集的圖片,在 “Window ” -> “Sprite Packer”面板里預(yù)覽圖集,可嘗試點(diǎn)擊左上角的“Pack”按鈕立即打包;
?
不同圖片如何合并至一個(gè)圖集?
-
選中需要打包圖集的圖片,將其類型修改Sprite (2D and UI),修改其Packing Tag為你自定義的名字。不同的圖片,只要Tag相同,就可以打包到同一個(gè)圖集里面。
打圖集策略:
(1)DefaultPackerPolicy:是默認(rèn)的打包方式,也是矩形打包方式。他會(huì)把所有的小圖按照矩形的方式來(lái)排列,如果寬高不一樣的圖片,它們會(huì)自動(dòng)補(bǔ)齊,使用方式就是tag設(shè)置時(shí)加上”[RECT]圖集名”來(lái)設(shè)置。
(2)TightPackerPolicy:是緊密打包方式,也就是盡可能的把圖片都打包在圖集上,這種方式要比DefaultPackerPolicy打包的圖片更多一些,也就是更省空間,使用方式就是tag設(shè)置時(shí)加上”[TIGHT]圖集名”來(lái)設(shè)置。
(3)TightRotateEnabledPackerPolicy:是緊密可旋轉(zhuǎn)打包方式,也就是使用緊密打包,并且允許精靈進(jìn)行旋轉(zhuǎn)。
(7)設(shè)計(jì)UI,幾個(gè)Image使用同一個(gè)圖集的不同元素,發(fā)現(xiàn)四個(gè)Image一次性渲染成功。
?
?
三:SpriteAtlas使用
Sprite Atlas 針對(duì)現(xiàn)有的圖集打包系統(tǒng)Sprite Packer在性能和易用性上的不足,進(jìn)行了全面改善。除此之外,相比Sprite Packer,Sprite Atlas將對(duì)精靈更多的控制權(quán)交還給用戶。由用戶來(lái)掌控圖集的打包過(guò)程以及加載時(shí)機(jī),更加利于對(duì)系統(tǒng)性能的控制。設(shè)置Edit-->Project Settings -->Editor --->Mode為Always Enable。
Sprite Atlas的主要有以下三個(gè)功能:
1.創(chuàng)建、編輯圖集以及設(shè)定圖集參數(shù)
2.添加圖集Variant(變種)
3.運(yùn)行時(shí)訪問(wèn)圖集
下面我們分別講解
3.1 創(chuàng)建、編輯圖集及參數(shù)設(shè)定
在Unity 2017.1版本之后,SpriteAtlas是一種資源,右擊 Asset ---> Create --->SpriteAtlas 可以像其它資源一樣在Unity中創(chuàng)建,例如預(yù)制件、場(chǎng)景等。
這里可以支持多種類型,包括單個(gè)Sprite、Sliced Sprite、文件夾,以及這些類型的任意組合。
操作更加方便,對(duì)用戶更友好。可以將文件夾,紋理或精靈分配給Sprite Atlas。可以將整個(gè)文件夾分配給Sprite Atlas資產(chǎn),該文件夾中的所有紋理(包括子文件夾)都將被打包,使用起來(lái)非常方便。
此外,在檢視窗口上還可以看到圖集的一些參數(shù)設(shè)定,例如:打包時(shí)是否支持精靈旋轉(zhuǎn)(Allow Rotation)、貼圖的采樣模式(Filter Mode)、壓縮方式(Compression)等等。 ? 在最下方的預(yù)覽窗口中,可以查看圖集的生成效果。這樣就可以很清楚的知道圖集的打包方式是否合理,是否存在大量被浪費(fèi)的空間。
設(shè)計(jì)UI,添加幾個(gè)Image,使用SpriteAtlas圖集內(nèi)部的圖片作為Image原圖片,發(fā)現(xiàn)DrawCall只需要一次就可以完成。
2.添加圖集Variant(變種)
所謂Variant,就是指原有圖集的一個(gè)變種。它會(huì)復(fù)制原有圖集的貼圖,并根據(jù)一個(gè)比例系數(shù)來(lái)調(diào)整復(fù)制貼圖的大小。
這樣的Variant通常用于為高分辨率和低分辨率的屏幕準(zhǔn)備不同的圖集。
因?yàn)槿绻粶?zhǔn)備一套高分辨率的圖集,在低分辨率的設(shè)備上占用內(nèi)存過(guò)多。反之,如果只準(zhǔn)備一套低分辨率圖集,在高分辨率的設(shè)備上就會(huì)模糊。
通過(guò)Atlas Variant就可以很方便地解決該問(wèn)題。如下圖所示,SpriteAtlas .spriteatlas是新建的一個(gè)低清圖集,在檢視窗口中將Type設(shè)為Variant,Master Atlas設(shè)為SpriteAtlas。這里為了與原圖進(jìn)行更明顯的對(duì)比,將Scale設(shè)為0.1, 點(diǎn)擊Pack Preview。
?
?
3.運(yùn)行時(shí)訪問(wèn)圖集
我們經(jīng)常會(huì)在代碼中切換ui的圖片,所以就需要單獨(dú)加載圖集中的每個(gè)精靈。
這樣做的好處是,讓用戶可以更加直接地隨時(shí)編輯圖集,而且不用去單獨(dú)加載圖集中的每個(gè)精靈。
下面是一段動(dòng)態(tài)換裝的代碼,該腳本通過(guò)LoadAsset加載SpriteAtlas類型的資源,再通過(guò)SpriteAtlas的GetSprite接口獲取圖集中的精靈,最后將精靈傳遞給SpriteRenderer。相較于基于Sprite Packer的實(shí)現(xiàn),整個(gè)過(guò)程要簡(jiǎn)單直接的多。
? using UnityEditor; using UnityEngine; using UnityEngine.U2D; ? public class SpriteAtlasExample : MonoBehaviour {void Start(){void Start(){//加載圖集SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/Hero.spriteatlas");//獲取圖集下的所有SpriteSprite[] sp = new Sprite[atlas.spriteCount];atlas.GetSprites(sp);print(sp.Length);//根據(jù)小圖名稱獲取對(duì)應(yīng)的SpriteSprite sprite = atlas.GetSprite("nxxg");if (sprite != null){GetComponent<SpriteRenderer>().sprite = sprite;}}} } using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.U2D; ? public class SpriteAtlasMgr : MonoBehaviour {public static SpriteAtlasMgr instance;private void Awake(){instance = this;}public Dictionary<string, SpriteAtlas> atlas = new Dictionary<string, SpriteAtlas>();public void AddSpriteAtlas(string name) { //}public void RemoveAtlas(string name) {//}public Sprite GetSpriteFromAtlas(string sname) {//....return null;}public Sprite GetSpriteFromAtlas(string atlasname, string sname){//....return null;}// public static SpriteAtlasMgr// Start is called before the first frame updatevoid Start(){} ?// Update is called once per framevoid Update(){} } ??
四:TexturePacker使用
(1)使用Texture Packer打包圖集時(shí),需要將小圖導(dǎo)入Texture Packer,然后進(jìn)行打包,打包的格式要注意是"Unity - Texture2D sprite sheet"(有一些低版本的TP是沒(méi)有這個(gè)格式的),TexturePacker官網(wǎng):https://www.codeandweb.com/texturepacker。 下載最新版本安裝即可
?
(2)將圖片或者文件夾拖動(dòng)至空白處,設(shè)置導(dǎo)出的圖片名字以及數(shù)據(jù)文件。
(3)點(diǎn)擊右上角【發(fā)布精靈表】,不用作其他修改,將這兩個(gè)文件放在工程資源中,這時(shí)從工程看這只是一張大圖,并不能算是一個(gè)圖集,使用里面的小圖(這時(shí)雖然可以用unity3d自帶功能,手動(dòng)對(duì)圖片進(jìn)行裁剪,但裁剪的小圖大小基本是不對(duì)的)。
?
(4)接下來(lái)需要下載并導(dǎo)入一個(gè)Unity3d的插件,TexturePacker自己出的的一個(gè)插件(TexturePacker Importer),插件鏈接:https://www.assetstore.unity3d.com/en/#!/content/16641,下載并成功導(dǎo)入之后,不用寫(xiě)任何代碼,也不用做任何操作,插件會(huì)自動(dòng)根據(jù).tpsheet文件,將剛才打包好并導(dǎo)入工程的大圖自動(dòng)裁剪成小圖,如下圖所示:
?
我們只需像使用單獨(dú)小圖一樣,將圖集里的小圖拖進(jìn)Source Image里即可。這時(shí)我們還只能在編輯器里使用圖集。
5、有時(shí)候,我們還需要在程序中動(dòng)態(tài)加載圖集并使用圖集里的小圖。unity3d 并沒(méi)有明確api說(shuō)明我們?nèi)绾斡眠@種圖集,而常用Resources.Load()加載只能返回單獨(dú)的一個(gè)圖片紋理,所以我們用另一個(gè)方法 Resources.LoadAll();加載整一張圖集,此方法會(huì)返回一個(gè)Object[],里面包含了圖集的紋理 Texture2D和圖集下的全部Sprite,所以我們就可以根據(jù)object 的類型和名字找到我們需要的某張小圖片。
6、下面整理了圖集紋理的管理類,去統(tǒng)一管理加載,是一個(gè)單例類,找個(gè)不被銷(xiāo)毀的GameObject綁定就行, 代碼比較簡(jiǎn)單,用一個(gè)Dictionary按圖集的路徑過(guò)key將加載過(guò)的圖集緩存起來(lái),需要時(shí)再由外部刪除掉,如下代碼所示:
using UnityEngine; using System.Collections; using System.Collections.Generic; ? //紋理圖集加載管理 public class TextureMgr : MonoBehaviour { private static GameObject m_pMainObject; private static TextureMgr m_pContainer = null; ? public static TextureMgr getInstance(){if(m_pContainer == null){m_pContainer = m_pMainObject.GetComponent<TextureMgr> ();} ?return m_pContainer; } ?private Dictionary<string, Object[]> m_pAtlasDic;//圖集的集合 void Awake(){ initData (); } private void initData(){ TextureMgr.m_pMainObject = gameObject;m_pAtlasDic = new Dictionary<string, Object[]> ();}//加載圖集上的一個(gè)精靈public Sprite LoadAtlasSprite(string _spriteAtlasPath,string _spriteName){Sprite _sprite = FindSpriteFormBuffer (_spriteAtlasPath,_spriteName);if (_sprite == null) {Object[] _atlas = Resources.LoadAll (_spriteAtlasPath);m_pAtlasDic.Add (_spriteAtlasPath,_atlas);_sprite = SpriteFormAtlas (_atlas,_spriteName);}return _sprite; ? } ? //刪除圖集緩存 public void DeleteAtlas(string _spriteAtlasPath){if (m_pAtlasDic.ContainsKey (_spriteAtlasPath)) {m_pAtlasDic.Remove (_spriteAtlasPath);} } //從緩存中查找圖集,并找出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; } ? //從圖集中,并找出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];}}} ?Debug.LogWarning ("圖片名:"+_spriteName+";在圖集中找不到");return null;} } ??
使用代碼如下:
public class LoadImage : MonoBehaviour {public Image parrotImage;// Start is called before the first frame updatevoid Start(){Sprite _sprite = TextureMgr.getInstance().LoadAtlasSprite("parrot", "hlb23");parrotImage.sprite = _sprite;} }?
總結(jié)
以上是生活随笔為你收集整理的Unity UGUI图集专题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: UGUI图集制作
- 下一篇: 新疆独库公路,一生一定要走一次!