Unity3d运行时程序创建NGUI图集

       前言,由于现在公司手头上的项目使用的 Unity3d版本为4.0.0f7,所有这里我用的 NGUI版本为2.6.3。
      项目中UI经常要用到动态加载图片,比较简单的方法是使用UITexture控件,这样只用3W类下载好图片后直接给
UITexture控件赋值就好了,缺点是 DrawCall太高了,一个UITexture一个DrawCall,通常只有是背景图片这种才会使用 UITexture控件,如果是下拉列表项,我们通常都是使用的UISprite控件,这时就需要我们在程序运行时,由程序创建图集,给 UISprite控件使用

请先看一下帖子:http://www.unitymanual.com/thread-16004-1-1.html
帖子的第一种方法其实已经说明了如何在程序中创建图集,只不过他这里是使用一张图片做成图集,再给 UISprite控件使用。
=====================
============= ================================
public class ImageLoader : MonoBehaviour {
 
//需要加载动态图片的对象
 
public UISprite m_img;
 
//自用的Atlas
 
private UIAtlas m_uiAtlas;
 
///
 
/// 加载的贴图
 
///
 
/// Tex.
 
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 = new Material(shader);
 
m_uiAtlas = this.gameObject.AddComponent();
 
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;
 
}
 
}
============================================================
            我们工作中常常遇到的是需要将多张图片制作成一个图集,再给多个UISprite控件使用,其实看懂了上面的代码运行时如何生成图集,再结合平常在编辑器中制作图集,答案就已经出来了。请大家好好看看NGUI的编辑器脚本UIAtlasMaker,也就是我们平常在编辑器中制作图集时用的脚本。我们 缺少的仅仅是将多张图片 PackTextures(打包)成一张大图(也就是我们的图集啦),其实 UIAtlasMaker脚本那么长,核心的操作也就是为了 PackTextures,也就是unity3d的API里 Texture2D.PackTextures函数,这里大家可以参考我以前转的别人的一篇关于该函数用法的文章:http://blog.sina.com.cn/s/blog_930ffa0b0102uyl8.html
和一篇别人分析 UIAtlasMaker脚本的文章:http://dsqiu.iteye.com/blog/1967088
          好了,最后就是我将 UIAtlasMaker脚本里打包操作的函数拔出来后的工具类了,只有 CreatAtlasFromTex这一个对外使用的函数。使用时只需要传人个UIAtlas组件和图片LIST就可以了,图集生成好后,UISprite控件就可以使用该动态图集了,这样好多个 UISprite控件组成的下拉列表项只占一个 DrawCall。
=============================CreatAtlas.cs=============================
using UnityEngine;
using System.Collections.Generic;

///
/// 运行时创建NGUI图集,NGUI2.6.3
///
public static class CreatAtlas {

    classSpriteEntry {
       public Texture2Dtex;    //Sprite texture -- original texture or a temporary texture
       public Rectrect;       // Sprite'souter rectangle within the generated texture atlas
       public int minX =0;    //Padding, if any (set if the sprite is trimmed)
       public int maxX = 0;
       public int minY = 0;
       public int maxY = 0;
       public bool temporaryTexture =false;    //Whether the texture is temporary and should be deleted
    }

    staticShader s_shader = Shader.Find("Unlit/Transparent Colored");
    staticMaterial s_mat = new Material(s_shader);
    static ints_maximumAtlasSize = 2048;
    staticTextureFormat s_TextureFormat = TextureFormat.RGBA32;
  
    static voidInit ( UIAtlas uIAtlas ) {
       if ( uIAtlas.spriteMaterial == null ) {
           //准备材质球    
           uIAtlas.spriteMaterial = s_mat;
       }     
    }

    ///
    ///运行时创建NGUI图集,NGUI2.6.3
    ///
    ///使用该UIAtlas在运行时创建NGUI图集
    ///用雨创建图集的多张小图
    publicstatic void CreatAtlasFromTex ( UIAtlas uIAtlas, List textures ){    
       if ( null == textures || textures.Count <= 0 ) {
           Debug.LogWarning("textures is null or count <= 0 !!");
           return;
       }
       if ( null == uIAtlas ) {
           Debug.LogWarning("uIAtlas is null");
           return;
       } else {
           Init(uIAtlas);

           // 设定贴图,将小图映射为SpriteEntry
           List sprites = CreateSprites(textures);
           // 将多个小图PackTexture为一张大图,给图集用
           uIAtlas.spriteMaterial.mainTexture = UpdateTexture(uIAtlas,sprites);
           ReplaceSprites(uIAtlas, sprites);
       }     
    }

    #region copyUIAtlasMaker编辑器脚本

    static ListCreateSprites (List textures) {
       List list = new List( );

       foreach (Texture tex in textures) {
           Texture2D oldTex = tex as Texture2D;
           if (oldTex == null) continue;
           // If we want to trim transparent pixels, there is more work to bedone
           Color32[ ] pixels = oldTex.GetPixels32( );

           int xmin = oldTex.width;
           int xmax = 0;
           int ymin = oldTex.height;
           int ymax = 0;
           int oldWidth = oldTex.width;
           int oldHeight = oldTex.height;

           // Find solid pixels
           for (int y = 0, yw = oldHeight; y < yw; ++y) {
               for (int x = 0, xw = oldWidth; x < xw; ++x) {
                   Color32 c = pixels[y * xw + x];

                   if (c.a != 0) {
                       if (y < ymin) ymin = y;
                       if (y > ymax) ymax = y;
                       if (x < xmin) xmin = x;
                       if (x > xmax) xmax = x;
                   }
               }
           }

           int newWidth = (xmax - xmin) + 1;
           int newHeight = (ymax - ymin) + 1;

           // If the sprite is empty, don't do anything with it
           if (newWidth > 0 && newHeight > 0) {
               SpriteEntry sprite = new SpriteEntry( );
               sprite.rect = new Rect(0f, 0f, oldTex.width, oldTex.height);

               // If the dimensions match, then nothing was actually trimmed
               if (newWidth == oldWidth && newHeight == oldHeight) {
                   sprite.tex = oldTex;
                   sprite.temporaryTexture = false;
               } else {
                   // Copy the non-trimmed texture data into a temporary buffer
                   Color32[ ] newPixels = new Color32[newWidth * newHeight];

                   for (int y = 0; y < newHeight; ++y) {
                       for (int x = 0; x < newWidth; ++x) {
                           int newIndex = y * newWidth + x;
                           int oldIndex = (ymin + y) * oldWidth + (xmin + x);
                           newPixels[newIndex] = pixels[oldIndex];
                       }
                   }

                   // Create a new texture
                   sprite.temporaryTexture = true;
                   sprite.tex = new Texture2D(newWidth, newHeight);
                   sprite.tex.name = oldTex.name;
                   sprite.tex.SetPixels32(newPixels);
                   sprite.tex.Apply( );

                   // Remember the padding offset
                   sprite.minX = xmin;
                   sprite.maxX = oldWidth - newWidth - xmin;
                   sprite.minY = ymin;
                   sprite.maxY = oldHeight - newHeight - ymin;
               }
               list.Add(sprite);
           }
       }
       return list;
    }

    staticTexture2D UpdateTexture (UIAtlas atlas, List sprites) {

       Texture2D tex = new Texture2D(1, 1, s_TextureFormat, false);
       PackTextures(tex, sprites);
       atlas.spriteMaterial.mainTexture = tex;
       return tex;
    }

    static voidPackTextures (Texture2D tex, List sprites) {
       Texture2D[ ] textures = new Texture2D[sprites.Count];
       for (int i = 0; i < sprites.Count; ++i) textures[i] =sprites[i].tex;

       Rect[ ] rects = tex.PackTextures(textures, 1,s_maximumAtlasSize);

       for (int i = 0; i < sprites.Count; ++i) {
           sprites[i].rect = NGUIMath.ConvertToPixels(rects[i], tex.width,tex.height, true);
       }
    }

    static voidReplaceSprites (UIAtlas atlas, List sprites) {
       // Get the list of sprites we'll be updating
       List spriteList = atlas.spriteList;
       List kept = new List( );

       // The atlas must be in pixels
       atlas.coordinates = UIAtlas.Coordinates.Pixels;

       // Run through all the textures we added and add them as sprites tothe atlas
       for (int i = 0; i < sprites.Count; ++i) {
           SpriteEntry se = sprites[i];
           UIAtlas.Sprite sprite = AddSprite(spriteList, se);
           kept.Add(sprite);
       }

       // Remove unused sprites
       for (int i = spriteList.Count; i > 0; ) {
           UIAtlas.Sprite sp = spriteList[--i];
           if (!kept.Contains(sp)) spriteList.RemoveAt(i);
       }
       atlas.MarkAsDirty( );
    }

    staticUIAtlas.Sprite AddSprite (List sprites, SpriteEntry se) {
       UIAtlas.Sprite sprite = null;

       // See if this sprite already exists
       foreach (UIAtlas.Sprite sp in sprites) {
           if (sp.name == se.tex.name) {
               sprite = sp;
               break;
           }
       }

       if (sprite != null) {
           float x0 = sprite.inner.xMin - sprite.outer.xMin;
           float y0 = sprite.inner.yMin - sprite.outer.yMin;
           float x1 = sprite.outer.xMax - sprite.inner.xMax;
           float y1 = sprite.outer.yMax - sprite.inner.yMax;

           sprite.outer = se.rect;
           sprite.inner = se.rect;

           sprite.inner.xMin = Mathf.Max(sprite.inner.xMin + x0,sprite.outer.xMin);
           sprite.inner.yMin = Mathf.Max(sprite.inner.yMin + y0,sprite.outer.yMin);
           sprite.inner.xMax = Mathf.Min(sprite.inner.xMax - x1,sprite.outer.xMax);
           sprite.inner.yMax = Mathf.Min(sprite.inner.yMax - y1,sprite.outer.yMax);
       } else {
           sprite = new UIAtlas.Sprite( );
           sprite.name = se.tex.name;
           sprite.outer = se.rect;
           sprite.inner = se.rect;
           sprites.Add(sprite);
       }

       float width = Mathf.Max(1f, sprite.outer.width);
       float height = Mathf.Max(1f, sprite.outer.height);

       // Sprite's padding values are relative to width and height
       sprite.paddingLeft = se.minX / width;
       sprite.paddingRight = se.maxX / width;
       sprite.paddingTop = se.maxY / height;
       sprite.paddingBottom = se.minY / height;
       return sprite;
    }

    #endregioncopy UIAtlasMaker编辑器脚本

}
=============================CreatAtlas.cs=============================

原文地址:http://blog.sina.com.cn/s/blog_930ffa0b0102v5t0.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值