Unity3D-NGUI動態載入圖片
阿新 • • 發佈:2019-01-04
NGUI提供了很方便的UIAtlas,其主要作用是改進DrawCall,把眾多圖片整合在一張貼圖上,由於UNITY3D簡單易用的好處,所以只是用原生的GUI很容易忽視DrawCall的問題,所以NGUI為了改進,才有了UIAtlas。當然NGUI還做了很多優化。
這裡主要還是介紹如何利用UISprite來動態的載入圖片。NGUI所提供的UIAtlas雖然好用,但只能在Editor內生成貼圖和prefab以供UISprite使用。為了能夠讓遊戲資源與遊戲本體儘可能的分離,特別是遊戲資源需要動態更新的情況。很多時候,都需要動態載入,動態設定UIAtlas。
這裡主要介紹2個方法。
方法1:直接在程式碼中建立和設定UIAtlas並對UISprite進行顯示。這種方法可以對任何零散的貼圖進行載入,但缺點是浪費DrawCall,主要應用在特別零散的貼圖資源上。
public class ImageLoader : MonoBehaviour { //需要載入動態圖片的物件 public UISprite m_img; //自用的Atlas private UIAtlas m_uiAtlas; /// <summary> /// 載入的貼圖 /// </summary> /// <param name="tex">Tex.</param> public void ImageLoad(Texture2D tex) { if(tex == null) { return; } if(tex.name == m_img.spriteName) { return; } //準備物件和材質球 if(m_uiAtlas == null) { Material mat; Shader shader = Shader.Find("Unlit/Transparent Colored"); mat = newMaterial(shader); m_uiAtlas = this.gameObject.AddComponent<UIAtlas>(); m_uiAtlas.spriteMaterial = mat; } //設定貼圖 m_uiAtlas.spriteMaterial.mainTexture = tex; m_uiAtlas.coordinates = UIAtlas.Coordinates.Pixels; //為對應UISprite介面,給Atlas加物件 UIAtlas.Sprite sprite = new UIAtlas.Sprite(); sprite.name = tex.name; sprite.outer = sprite.inner = new Rect(0f, 0f, tex.width, tex.height); m_uiAtlas.spriteList.Clear(); m_uiAtlas.spriteList.Add(sprite); //設定完成 m_img.atlas = m_uiAtlas; m_img.spriteName = tex.name; } }
方法2:將整個UIAtlas及其貼圖打包,而後形成資源,駐留在記憶體中(僅僅是指向資源的指標),UNITY3D會根據引用來確定貼圖是否直接放實際記憶體中。這種方法更適合ICON之類有規律可以配置整合的資源。缺點是需要維護。
//從資原始檔夾載入打包成assetBundle的ICON資原始檔 private IEnumerator LoadResIcon() { //準備好資源們 string strFormat = ResourcePath.GetPath() + "UI/{0}"; string strFilePath = ""; for(int i = 0 , nMax = GameConfig.Instance.IconSet.strIcons.Length; i < nMax ; i++) { string strAssetName = GameConfig.Instance.IconSet.strIcons[i]; strFilePath = string.Format(strFormat, strAssetName); WWW tmp_www = null; try { tmp_www = new WWW(strFilePath); } catch { tmp_www = null; } if(tmp_www==null) { continue; } yield return tmp_www; if(tmp_www.error !=null) { tmp_www.Dispose(); tmp_www = null; yield break; } AssetBundle tmp_assetBundle = tmp_www.assetBundle; tmp_www.Dispose(); tmp_www = null; UIAtlas atlas = tmp_assetBundle.Load(strAssetName,typeof(UIAtlas)) as UIAtlas; tmp_assetBundle.Unload(false); GameConfig.Instance.IconSet.SaveUIAtlas(i, atlas); } yield return null; }
管理UIAtlas
public class IconSet { public string[] strIcons = { "A1_Atlas", "A2_Atlas", "A3_Atlas", }; public UIAtlas[] m_AtlasData; Dictionary<string, int> m_dicIcon; public IconSet() { m_AtlasData = new UIAtlas[strIcons.Length]; m_dicIcon = new Dictionary<string, int>(); } //儲存Atlas的完整資訊 public void SaveUIAtlas(int nIndex, UIAtlas UIvalue) { m_AtlasData[nIndex] = UIvalue; foreach (string iconNames in UIvalue.GetListOfSprites()) { m_dicIcon[(string)iconNames.Clone()] = nIndex;//將所有的ICONNAME資訊記錄並且繫結成索引,以便查詢 } } //根據ICONNAME找出對應UIATLAS public UIAtlas FindAtlasBySpriteName(string name) { int nAtlasIndex = 0; if (m_dicIcon.TryGetValue(name, out nAtlasIndex)) { return m_AtlasData[nAtlasIndex]; } return null; } }
實際使用的範例:
//設定顯示物件 UISprite sprite = this.GetComponent<UISprite>(); sprite.atlas = GameConfig.Instance.IconSet.FindAtlasBySpriteName("Icon001"); sprite.spriteName = "Icon001";
總結:
以上兩種方法基本能夠應對大部分UI的現實問題,ImageLoader本身傳入的是Texture2D,所以,即便是RenderTexture也沒問題,都能與NGUI和諧相處。加以擴充套件的話,就是讓另一個攝像機匯出的東西和當前NGUI擺的UI結合。