[Unity优化]减少内存占用:贴图优化

参考链接:

http://blog.csdn.net/u010153703/article/details/45502895

http://blog.csdn.net/candycat1992/article/details/42127811

http://www.cnblogs.com/joeshifu/p/5489906.html


这是本篇文章的主角:



0.

贴图压缩:
Android平台使用ETC1格式压缩,但它不支持含Alpha通道的图片压缩。
所以一般把RGB和ALPHA分离出来,rgb值从RGB图获取,a值从Alpha图获取。
随着OPENGL ES 3.0的发布,ETC2也出了,支持Alpha通道,但就目前的市场,支持的机型还比较少,所以可以不用考虑。


IOS平台使用PVRTC格式压缩,它支持含Alpha通道的图片压缩。


贴图设置:

宽高为2的n次方
Read/Write Enabled不勾
Generate Mip Maps不勾



1.首先先理解一下Texture2D.GetPixels()这个方法,它会返回纹理中所有像素的颜色值,其中有一个参数是miplevel,通过调节下图中右上方那个滑动按钮即可看到不同miplevel下的样子。

miplevel为0时(默认),像素数目最多,最清晰:


miplevel为3时,有点像素风的感觉:


那么miplevel不同时,真正的差别究竟是什么呢,测试一下:

using UnityEngine;
using System.Collections;

public class TestTexture : MonoBehaviour {

    //需要先将TextureType设置为Advanced,然后设置Read/Write Enabled为true
    //如果图片宽高不为2的n次方,建议将NonPowerOf2设置为非None的选项,方便测试
    public Texture2D texture2D;
    private Color[] colors;

	void Start () 
    {
        //api:public Color[] GetPixels(int miplevel = 0);
        //以一张512x512的图为例,输出为:
        //262144,262144,65536,16384
        //结论:miplevel每增加1,则宽高同时除以2
        colors = texture2D.GetPixels();
        Debug.Log(colors.Length);
        colors = texture2D.GetPixels(0);
        Debug.Log(colors.Length);
        colors = texture2D.GetPixels(1);
        Debug.Log(colors.Length);
        colors = texture2D.GetPixels(2);
        Debug.Log(colors.Length);
	}

}

miplevel的取值范围:以一张512x512的图为例(512,即2的9次方),那么取值就是0到9。

那么知道miplevel之后,再说一下Generate Mip Maps,下图分别是勾选和不勾选的区别。勾选后,会生成各种不同miplevel值的纹理,当纹理距离摄像机较远时,会自动使用先前生成的纹理,优点是减少运算量,缺点是增加内存占用;不勾选,则相反。

  


2.那么回到正题,使用脚本批量处理,分离通道:

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;

/// <summary>
/// 选择文件夹或者选择单个多个图片,然后右键即可
/// </summary>
public class SeperateChannel {

    private static List<string> allFiles;
    private static bool mipmap = false;

    [MenuItem("Assets/Seperate Channel")]
    static void Seperate()
    {
        string path = GetFullPath(Selection.objects[0]);
        allFiles = new List<string>();

        //如果选择的是文件夹,就获取文件夹下的所有文件
        //否则就获取选择的文件
        if (!path.Contains(".")) GetAllFiles(path);
        else GetAllFiles();
        allFiles.RemoveAll((s) => { return s.Contains("meta"); });

        string[] suffix = new string[] { ".psd", ".tga", ".png", ".jpg", ".bmp", ".tif", ".gif" };
        string[] convert = new string[] { "_RGB", "_Alpha" };//经处理后的纹理会带有这些字样
        for (int i = 0; i < allFiles.Count; i++)
        {
            bool needHandle = false;

            //经过两个for循环筛选出要处理的纹理
            for (int j = 0; j < suffix.Length; j++)
            {
                if (allFiles[i].EndsWith(suffix[j]))
                {
                    needHandle = true; 
                    break;
                }
            }

            for (int j = 0; j < convert.Length; j++)
            {
                if (allFiles[i].Contains(convert[j]))
                {
                    needHandle = false;
                    break;
                }
            }

            if (!needHandle) continue;
            Debug.Log(allFiles[i]);


            allFiles[i] = GetAssetPath(allFiles[i]);
            TextureImporter ti = TextureImporter.GetAtPath(allFiles[i]) as TextureImporter;
            ti.isReadable = true;

            Texture2D sourceTex = AssetDatabase.LoadAssetAtPath<Texture2D>(allFiles[i]);
            Color[] sourceColor = sourceTex.GetPixels();

            Texture2D rgbTex = new Texture2D(sourceTex.width, sourceTex.height, TextureFormat.RGB24, mipmap);
            rgbTex.SetPixels(sourceColor);
            WriteTexture(rgbTex, allFiles[i], true);

            Texture2D alphaTex = new Texture2D(sourceTex.width, sourceTex.height, TextureFormat.RGB24, mipmap);
            Color[] c = new Color[sourceColor.Length];
            for (int j = 0; j < c.Length; j++)
            {
                c[j] = new Color(sourceColor[j].a, 0, 0);
            }
            alphaTex.SetPixels(c);
            WriteTexture(alphaTex, allFiles[i], false);
        }

        AssetDatabase.Refresh();
        Debug.Log("分离完毕");
    }

    //获取完整的路径(用于递归遍历)
    public static string GetFullPath(Object assetObj)
    {
        string path = AssetDatabase.GetAssetPath(assetObj);
        path = Application.dataPath + path;
        path = path.Replace("AssetsAssets", "Assets");
        return path;
    }

    //获取以Asset开头的路径
    public static string GetAssetPath(string fullPath)
    {
        fullPath = fullPath.Substring(fullPath.IndexOf("Assets"));
        return fullPath;
    }

    //获取选择的所有文件
    public static void GetAllFiles()
    {
        for (int i = 0; i < Selection.objects.Length; i++)
        {
            string s = GetFullPath(Selection.objects[i]);
            allFiles.Add(s);
        }
    }

    //递归获取一个根目录下的所有文件  
    public static void GetAllFiles(string dir)
    {
        string[] files = Directory.GetFiles(dir);
        foreach (var item in files)
        {
            allFiles.Add(item);
        }

        string[] dirs = Directory.GetDirectories(dir);
        foreach (var item in dirs)
        {
            GetAllFiles(item);
        }
    }

    //写入
    public static void WriteTexture(Texture2D tex, string assetPath, bool rgb)
    {
        string path = Application.dataPath + assetPath;
        path = path.Replace("AssetsAssets", "Assets");
        string suffix = path.Substring(path.IndexOf("."));

        if (rgb) path = path.Replace(suffix, "_RGB" + suffix);
        else path = path.Replace(suffix, "_Alpha" + suffix);
        Debug.Log(path);

        tex.Apply();
        byte[] bytes = tex.EncodeToPNG();
        File.WriteAllBytes(path, bytes);
        AssetDatabase.Refresh();

        //重新导入
        path = GetAssetPath(path);
        TextureImporter ti = TextureImporter.GetAtPath(path) as TextureImporter;
        ti.isReadable = false;
        ti.textureFormat = TextureImporterFormat.AutomaticCompressed;
        AssetDatabase.ImportAsset(path);
    }

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值