关于NGUI动态加载图片,并且实现动态打图集的过程

注:一些代码是在网上找的,太多就没有写。

   前几天做项目,遇到所要用的的大量图片都必须从网上下载,当时用的NGUI做的UI界面,当时上网找了好多,都不行,最后找一篇还差不多,但是也不好用,我重新捋了一遍;

    首先,我想到的就是用NGUI的UITexture组件的UITexture.mainTexture来直接将WWW获取的图片给赋值上去,这样很简单,但是有新的问题,图片量比较大,如果图片少的话可以使用这种方法。

    其次,换UI界面了,用UGUI做,UGUI是自动打图集,所以说方便,也可以用一两个RawTexture,但是UGUI要显示图片,必须将图片转换成Sprite,这也是一个难点,但是能够解决,可以将WWW 获取的图片用代码转换成Sprite格式,(转换这篇博客就不说了,下一篇我在说一下,有不会的可以看一看)。

    最后,就是本博客的主要内容;NGUI动态打图集:

    研究了好长时间,这种方法的只能是将图集打出来,但是不能弄成预设,图集打在一个空的GameObject上面,直接上代码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class NGUIAtlasMaker : MonoBehaviour {

    public static bool atlasTrimming = true;
    public static bool atlasPMA = false;
    public static bool unityPacking = false;
    public static int atlasPadding = 1;
    public static bool allow4096 = true;

    //主要就是继承UISpriteData,我们要修改它的类型
    public class SpriteEntry : UISpriteData
    {
        // Sprite texture -- original texture or a temporary texture
        public Texture2D tex;

        // Whether the texture is temporary and should be deleted
        public bool temporaryTexture = false;
    }

    static int Compare(SpriteEntry a, SpriteEntry b)
    {
        if (a == null && b != null) return 1;
        if (a != null && b == null) return -1;

        int aPixels = a.width * a.height;
        int bPixels = b.width * b.height;

        if (aPixels > bPixels) return -1;
        else if (aPixels < bPixels) return 1;
        return 0;
    }

    //对于Android和IOS是不一样的
    static bool PackTextures(Texture2D tex, List<SpriteEntry> sprites)
    {
        Texture2D[] textures = new Texture2D[sprites.Count];
        Rect[] rects;

#if UNITY_3_5 || UNITY_4_0
    int maxSize = 4096;
#else
        int maxSize = SystemInfo.maxTextureSize;
#endif

#if UNITY_ANDROID || UNITY_IPHONE
    maxSize = Mathf.Min(maxSize, allow4096 ? 4096 : 2048);
#endif
        if (unityPacking)
        {
            for (int i = 0; i < sprites.Count; ++i) textures[i] = sprites[i].tex;
            rects = tex.PackTextures(textures, atlasPadding, maxSize);
        }
        else
        {
            sprites.Sort(Compare);
            for (int i = 0; i < sprites.Count; ++i) textures[i] = sprites[i].tex;
            rects = UITexturePacker.PackTextures(tex, textures, 4, 4, atlasPadding, maxSize);
        }

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

            if (Mathf.RoundToInt(rect.width) != textures[i].width) return false;

            SpriteEntry se = sprites[i];
            se.x = Mathf.RoundToInt(rect.x);
            se.y = Mathf.RoundToInt(rect.y);
            se.width = Mathf.RoundToInt(rect.width);
            se.height = Mathf.RoundToInt(rect.height);
        }
        return true;
    }

    static public void AddOrUpdate(UIAtlas atlas, Texture2D tex)
    {
        if (atlas != null && tex != null)
        {
            List<Texture> textures = new List<Texture>();
            textures.Add(tex);
            List<SpriteEntry> sprites = CreateSprites(textures);
            ExtractSprites(atlas, sprites);
            UpdateAtlas(atlas, sprites);
        }
    }

    static public void UpdateAtlas(UIAtlas atlas, List<SpriteEntry> sprites)
    {
        if (sprites.Count > 0)
        {

            if (UpdateTexture(atlas, sprites))
            {
                // Replace the sprites within the atlas
                ReplaceSprites(atlas, sprites);
            }

            // Release the temporary textures
            ReleaseSprites(sprites);
            return;
        }
        else
        {
            atlas.spriteList.Clear();
            NGUITools.Destroy(atlas.spriteMaterial.mainTexture);
            atlas.spriteMaterial.mainTexture = null;
        }

        atlas.MarkAsChanged();
    }

    /// <summary>
    /// Add a new sprite to the atlas, given the texture it's coming from and the packed rect within the atlas.
    /// </summary>

    static public UISpriteData AddSprite(List<UISpriteData> sprites, SpriteEntry se)
    {
        // See if this sprite already exists
        foreach (UISpriteData sp in sprites)
        {
            if (sp.name == se.name)
            {
                sp.CopyFrom(se);
                return sp;
            }
        }

        UISpriteData sprite = new UISpriteData();
        sprite.CopyFrom(se);
        sprites.Add(sprite);
        return sprite;
    }

    /// <summary>
    /// Create a list of sprites using the specified list of textures.
    /// </summary>
    /// 
    static public List<SpriteEntry> CreateSprites(List<Texture> textures)
    {
        List<SpriteEntry> list = new List<SpriteEntry>();

        foreach (Texture tex in textures)
        {
            Texture2D oldTex = tex as Texture2D;

            // If we aren't doing trimming, just use the texture as-is
            if (!atlasTrimming && !atlasPMA)
            {
                SpriteEntry sprite = new SpriteEntry();
                sprite.SetRect(0, 0, oldTex.width, oldTex.height);
                sprite.tex = oldTex;
                sprite.name = oldTex.name;
                sprite.temporaryTexture = false;
                list.Add(sprite);
                continue;
            }

            // If we want to trim transparent pixels, there is more work to be done
            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
            if (atlasTrimming)
            {
                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;
                        }
                    }
                }
            }
            else
            {
                xmin = 0;
                xmax = oldWidth - 1;
                ymin = 0;
                ymax = oldHeight - 1;
            }

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

            if (newWidth > 0 && newHeight > 0)
            {
                SpriteEntry sprite = new SpriteEntry();
                sprite.x = 0;
                sprite.y = 0;
                sprite.width = oldTex.width;
                sprite.height = oldTex.height;

                // If the dimensions match, then nothing was actually trimmed
                if (!atlasPMA && (newWidth == oldWidth && newHeight == oldHeight))
                {
                    sprite.tex = oldTex;
                    sprite.name = oldTex.name;
                    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);
                            if (atlasPMA) newPixels[newIndex] = NGUITools.ApplyPMA(pixels[oldIndex]);
                            else newPixels[newIndex] = pixels[oldIndex];
                        }
                    }

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

                    // Remember the padding offset
                    sprite.SetPadding(xmin, ymin, oldWidth - newWidth - xmin, oldHeight - newHeight - ymin);
                }
                list.Add(sprite);
            }
        }
        return list;
    }

    /// <summary>
    /// Release all temporary textures created for the sprites.
    /// </summary>

    static public void ReleaseSprites(List<SpriteEntry> sprites)
    {
        foreach (SpriteEntry se in sprites)
        {
            if (se.temporaryTexture)
            {
                NGUITools.Destroy(se.tex);
                se.tex = null;
            }
        }
        Resources.UnloadUnusedAssets();
    }

    static public void ReplaceSprites(UIAtlas atlas, List<SpriteEntry> sprites)
    {
        // Get the list of sprites we'll be updating
        List<UISpriteData> spriteList = atlas.spriteList;
        List<UISpriteData> kept = new List<UISpriteData>();

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

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

        // Sort the sprites so that they are alphabetical within the atlas
        atlas.SortAlphabetically();
        atlas.MarkAsChanged();
    }

    /// <summary>
    /// Extract the specified sprite from the atlas.
    /// </summary>
    /// 
    static public SpriteEntry ExtractSprite(UIAtlas atlas, string spriteName)
    {
        if (atlas.texture == null) return null;
        UISpriteData sd = atlas.GetSprite(spriteName);
        if (sd == null) return null;

        Texture2D tex = atlas.texture as Texture2D;
        SpriteEntry se = ExtractSprite(sd, tex);
        return se;
    }

    /// <summary>
    /// Extract the specified sprite from the atlas texture.
    /// </summary>

    static SpriteEntry ExtractSprite(UISpriteData es, Texture2D tex)
    {
        return (tex != null) ? ExtractSprite(es, tex.GetPixels32(), tex.width, tex.height) : null;
    }

    /// <summary>
    /// Extract the specified sprite from the atlas texture.
    /// </summary>

    static SpriteEntry ExtractSprite(UISpriteData es, Color32[] oldPixels, int oldWidth, int oldHeight)
    {
        int xmin = Mathf.Clamp(es.x, 0, oldWidth);
        int ymin = Mathf.Clamp(es.y, 0, oldHeight);
        int xmax = Mathf.Min(xmin + es.width, oldWidth - 1);
        int ymax = Mathf.Min(ymin + es.height, oldHeight - 1);
        int newWidth = Mathf.Clamp(es.width, 0, oldWidth);
        int newHeight = Mathf.Clamp(es.height, 0, oldHeight);

        if (newWidth == 0 || newHeight == 0) return null;

        Color32[] newPixels = new Color32[newWidth * newHeight];

        for (int y = 0; y < newHeight; ++y)
        {
            int cy = ymin + y;
            if (cy > ymax) cy = ymax;

            for (int x = 0; x < newWidth; ++x)
            {
                int cx = xmin + x;
                if (cx > xmax) cx = xmax;

                int newIndex = (newHeight - 1 - y) * newWidth + x;
                int oldIndex = (oldHeight - 1 - cy) * oldWidth + cx;

                newPixels[newIndex] = oldPixels[oldIndex];
            }
        }

        // Create a new sprite
        SpriteEntry sprite = new SpriteEntry();
        sprite.CopyFrom(es);
        sprite.SetRect(0, 0, newWidth, newHeight);
        sprite.temporaryTexture = true;
        sprite.tex = new Texture2D(newWidth, newHeight);
        sprite.tex.SetPixels32(newPixels);
        sprite.tex.Apply();
        return sprite;
    }

    /// <summary>
    /// Extract sprites from the atlas, adding them to the list.
    /// </summary>

    static public void ExtractSprites(UIAtlas atlas, List<SpriteEntry> finalSprites)
    {
        Texture2D tex = atlas.texture as Texture2D;

        if (tex != null)
        {
            Color32[] pixels = null;
            int width = tex.width;
            int height = tex.height;
            List<UISpriteData> sprites = atlas.spriteList;
            float count = sprites.Count;
            int index = 0;

            foreach (UISpriteData es in sprites)
            {
                bool found = false;

                foreach (SpriteEntry fs in finalSprites)
                {
                    if (es.name == fs.name)
                    {
                        fs.CopyBorderFrom(es);
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    if (pixels == null) pixels = tex.GetPixels32();
                    SpriteEntry sprite = ExtractSprite(es, pixels, width, height);
                    if (sprite != null) finalSprites.Add(sprite);
                }
            }
        }
    }

    static public bool UpdateTexture(UIAtlas atlas, List<SpriteEntry> sprites)
    {
        // Get the texture for the atlas
        Texture2D tex = atlas.texture as Texture2D;

        bool newTexture = tex == null;

        if (newTexture)
        {
            // Create a new texture for the atlas
            tex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
        }

        // Pack the sprites into this texture
        if (PackTextures(tex, sprites) && tex != null)
        {
            // Update the atlas texture
            if (newTexture)
            {
                if (atlas.spriteMaterial == null)
                {
                    Shader shader = Shader.Find(atlasPMA ? "Unlit/Premultiplied Colored" : "Unlit/Transparent Colored");
                    atlas.spriteMaterial = new Material(shader);
                }
                atlas.spriteMaterial.mainTexture = tex;
                ReleaseSprites(sprites);
            }
            return true;
        }
        else
        {
            return false;
        }
    }

    // save as ngui's
  
        public UITexturePacker(int width, int height, bool rotations)
        {
            Init(width, height, rotations);
        }

        public void Init(int width, int height, bool rotations)
        {
            binWidth = width;
            binHeight = height;
            allowRotations = rotations;

            Rect n = new Rect();
            n.x = 0;
            n.y = 0;
            n.width = width;
            n.height = height;

            usedRectangles.Clear();

            freeRectangles.Clear();
            freeRectangles.Add(n);
        }

        private struct Storage
        {
            public Rect rect;
            public bool paddingX;
            public bool paddingY;
        }

        public static Rect[] PackTextures(Texture2D texture, Texture2D[] textures, int width, int height, int padding, int maxSize)
        {
            if (width > maxSize && height > maxSize) return null;
            if (width > maxSize || height > maxSize) { int temp = width; width = height; height = temp; }

            // Force square by sizing up
            // sz modify
            //if (NGUISettings.forceSquareAtlas)
            if (forceSquareAtlas)
            {
                if (width > height)
                    height = width;
                else if (height > width)
                    width = height;
            }
            UITexturePacker bp = new UITexturePacker(width, height, false);
            Storage[] storage = new Storage[textures.Length];

            for (int i = 0; i < textures.Length; i++)
            {
                Texture2D tex = textures[i];
                if (!tex) continue;

                Rect rect = new Rect();

                int xPadding = 1;
                int yPadding = 1;

                for (xPadding = 1; xPadding >= 0; --xPadding)
                {
                    for (yPadding = 1; yPadding >= 0; --yPadding)
                    {
                        rect = bp.Insert(tex.width + (xPadding * padding), tex.height + (yPadding * padding),
                                         UITexturePacker.FreeRectChoiceHeuristic.RectBestAreaFit);
                        if (rect.width != 0 && rect.height != 0) break;

                        // After having no padding if it still doesn't fit -- increase texture size.
                        else if (xPadding == 0 && yPadding == 0)
                        {
                            return PackTextures(texture, textures, width * (width <= height ? 2 : 1),
                                                height * (height < width ? 2 : 1), padding, maxSize);
                        }
                    }
                    if (rect.width != 0 && rect.height != 0) break;
                }

                storage[i] = new Storage();
                storage[i].rect = rect;
                storage[i].paddingX = (xPadding != 0);
                storage[i].paddingY = (yPadding != 0);
            }

            texture.Resize(width, height);
            texture.SetPixels(new Color[width * height]);

            // The returned rects
            Rect[] rects = new Rect[textures.Length];

            for (int i = 0; i < textures.Length; i++)
            {
                Texture2D tex = textures[i];
                if (!tex) continue;

                Rect rect = storage[i].rect;
                int xPadding = (storage[i].paddingX ? padding : 0);
                int yPadding = (storage[i].paddingY ? padding : 0);
                Color[] colors = tex.GetPixels();

                // Would be used to rotate the texture if need be.
                if (rect.width != tex.width + xPadding)
                {
                    Color[] newColors = tex.GetPixels();

                    for (int x = 0; x < rect.width; x++)
                    {
                        for (int y = 0; y < rect.height; y++)
                        {
                            int prevIndex = ((int)rect.height - (y + 1)) + x * (int)tex.width;
                            newColors[x + y * (int)rect.width] = colors[prevIndex];
                        }
                    }

                    colors = newColors;
                }

                texture.SetPixels((int)rect.x, (int)rect.y, (int)rect.width - xPadding, (int)rect.height - yPadding, colors);
                rect.x /= width;
                rect.y /= height;
                rect.width = (rect.width - xPadding) / width;
                rect.height = (rect.height - yPadding) / height;
                rects[i] = rect;
            }
            texture.Apply();
            return rects;
        }
        
        。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  代码量挺大,我就不全写出来了,如果要深入研究,可以下载附件,这个脚本只是一个要被调用的脚本。

}

下面就是我们要调用的参数:
using UnityEngine;
using System.Collections;

public class NGUIAtlasMakerTest : MonoBehaviour {

    public UITexture tt;
    private Texture[] img;
    private Texture2D[] texs;
    public UISprite sprite;
    private UIAtlas atlas;

    void Start()
    {
        StartCoroutine(GetTupian());

        Invoke("TokeImage", 3.0f);
   
      
    }

    //此方法就是调用打图集的方法
    public void TokeImage()
    {
    //将下载的图片存储到texs中,进行动态打图集
        texs = new Texture2D[img.Length];
        for (int i = 0; i < img.Length; i++)
        {
            texs[i] = img[i] as Texture2D;
        }

        NGUIAtlasMaker.atlasTrimming = true;
        NGUIAtlasMaker.atlasPMA = atlas != null ? atlas.premultipliedAlpha : false;
        NGUIAtlasMaker.unityPacking = false;
        NGUIAtlasMaker.atlasPadding = 1;
        NGUIAtlasMaker.allow4096 = true;
        NGUIAtlasMaker.UITexturePacker.forceSquareAtlas = true;

        if (atlas == null)
        {
            atlas = this.gameObject.AddComponent<UIAtlas>();
        }
        string lastName = string.Empty;
        foreach (var tex in texs)
        {
            SZUIAtlasMakerRuntime.AddOrUpdate(atlas, tex);
            lastName = tex.name;
        }
        sprite.atlas = atlas;
        sprite.spriteName = lastName;
    }

 //图片下载过程(注意:我在这里只下载了一张图片,根据需要,你可以下载多张,只要存储到img数组或者texs数组中就行)
 这些都是很简单了,但是下载的图片是没有名字的,我想了个办法给命名了,
    IEnumerator GetTupian()
    {
        Debug.Log(1212);
        WWW www = new WWW("http://pic.baike.soso.com/p/20090711/20090711101754-314944703.jpg");
        yield return www;
        Texture2D tu = 
        //命名的过程 
        tu.name = "ttt";
        Debug.Log(www.texture .name);
        img = new Texture[1];
        for (int i = 0; i < img.Length ; i++)
        {
            img[i] = tu;
            
        }
        tt.mainTexture = img[0];
    }
    
    这种动态打图集,只能将图集打到一个空的GameObject上,,也就是说GameObject就是一个图集,但却不是预设,如果大家有什么好的建议或者方法,都可以分享出来,或者联系我


你可能感兴趣的:(NGUI动态获取图片打图集)