Unity內存優化(貼圖層面)


聊聊近況:
距離上一篇文章已經過了好久,主要原因是我懶了。公司項目也到了開始優化的階段,上網找的資料,看過了就忘。還是想把它整理一下,寫出來。其實我說的東西,網上都有,我只是搬運工而已。

貼圖壓縮:
Android平台使用ETC1格式壓縮。
目前主流的Android機型基本都支持ETC1格式壓縮。但ETC1只能支持非Alpha通道的圖片壓縮
所以一般把RGB和ALPHA分離出來,r值,g值,b值從RGB圖獲取,a值從Alpha圖里獲取。
隨着OPENGL ES 3.0的發布,etc2也出了,支持Alpha通道,但就目前的市場,支持的機型還比較少,所以可以不用考慮。

IOS平台使用PVRT壓縮紋理,它支持Alpha通道。

工具准備:
TexturePacker4.1.0及破解戳這里:鏈接:http://pan.baidu.com/s/1qYKNIQ4 密碼:s21o
我的第一篇文章也用過TexturePacker:http://www.shihuanjue.com/?p=16

實踐:
1.打開TexturePacker,選擇Unity-JOSN data,把美術給過來的散圖拖到TexturePacker里面,調整參數,最后Publish導出圖集(.tga)和小圖配置信息(.txt)。

 

2.打開Photoshop,拖入.tga
保存RGB圖:選中Alpha 1.右鍵。刪除該透明通道。然后將圖片存儲為_MainTex.png圖片。

保存ALPHA圖:我們可以在菜單中后退一步。或者重新打開沒有刪除透明通道的圖片。
選中Alpha 1. 按Ctrl + A 全選 ,再按 Ctrl + C 復制透明通道。
選中RGB,Ctrl + V 粘貼。
最后刪除Alpha 1 透明通道。將圖片保存為_AlphaTex.png。

我們項目還是用的還是NGUI,用NGUI做UIAtlas。

新建一個材質球,圖片用的是_MainTex.png,_AlphaTex.png
NGUI的原生Shader,是從一張圖上獲取RGBA的,現在我們需要從_AlphaTex.png上獲取a值。
所以拿來改改:

Shader "Unlit/Transparent Colored ETC1"
{
    Properties
    {
        _MainTex ("rgb tex", 2D) = "black" {}
        _AlphaTex("alpha tex",2D) = "white"{}
    }
 
    SubShader
    {
        LOD 100
 
        Tags
        {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }
 
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Offset -1, -1
        Blend SrcAlpha OneMinusSrcAlpha
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
 
            #include "UnityCG.cginc"
 
            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                fixed4 color : COLOR;
            };
 
            struct v2f
            {
                float4 vertex : SV_POSITION;
                half2 texcoord : TEXCOORD0;
                fixed4 color : COLOR;
            };
 
            sampler2D _MainTex;
            float4 _MainTex_ST;
 
            sampler2D _AlphaTex;
            float4 _AlphaTex_ST;
 
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texcoord = v.texcoord;
                o.color = v.color;
                return o;
            }
 
            fixed4 frag (v2f i) : COLOR
            {
                //fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
                //return col;
                fixed4 texcol = tex2D(_MainTex, i.texcoord); 
                fixed4 result = texcol;
                result.a = tex2D(_AlphaTex,i.texcoord).r*i.color.a;
                return result;
            }
            ENDCG
        }
    }
 
    SubShader
    {
        LOD 100
 
        Tags
        {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }
 
        Pass
        {
            Cull Off
            Lighting Off
            ZWrite Off
            Fog { Mode Off }
            Offset -1, -1
            ColorMask RGB
            AlphaTest Greater .01
            Blend SrcAlpha OneMinusSrcAlpha
            ColorMaterial AmbientAndDiffuse
 
            SetTexture [_MainTex]
            {
                Combine Texture * Primary
            }
        }
    }
}

把一開始TP導出的.txt拖到UIAtlas的TP Import上

效果:

肉眼看不出明顯差別,內存卻減少了不少。

RGB和ALPHA分離(腳本化):
用PS去分離,太慢。嘗試用腳本或者工具來自動化分離。

using UnityEngine;  
using System.Collections;  
using System.Collections.Generic;  
using UnityEditor;  
using System.IO;  
using System.Reflection; 
 
public class MaterialTextureForETC1_Old : MonoBehaviour 
{
    public static float sizeScale = 0.5f;   //the size decrease scale for alphaTexture  
    private static string texPath = Application.dataPath+"/TestSplitTex";
 
    [MenuItem("EffortForETC1/Seperate RGB and Alpha Channel for All Textures")]  
    static void SeperateAllTexturesRGBandAlphaChannel()  
    {  
        string[] paths = Directory.GetFiles(texPath, "*.*", SearchOption.AllDirectories);  
        foreach (string path in paths)  
        {  
            if (!string.IsNullOrEmpty(path) && IsTextureFile(path))   //full name  
            {  
                SeperateRGBAandlphaChannel(path);  
            }  
        }   
    }  
 
    #region process texture  
 
    static void SeperateRGBAandlphaChannel(string _texPath)  
    {  
        string assetRelativePath = GetRelativeAssetPath(_texPath);  
        SetTextureReadable(assetRelativePath);  
        Texture2D sourcetex = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(Texture2D)) as Texture2D;  //not just the textures under Resources file  
        if (!sourcetex)  
        {  
            Debug.Log("Load Texture Failed : " + assetRelativePath);  
            return;  
        }  
        if (!HasAlphaChannel(sourcetex))  
        {  
            Debug.Log("Texture does not have Alpha channel : " + assetRelativePath);  
            return;  
        }  
 
        Texture2D rgbTex = new Texture2D(sourcetex.width, sourcetex.height, TextureFormat.RGB24, true);  
        Texture2D alphaTex = new Texture2D((int)(sourcetex.width * sizeScale), (int)(sourcetex.height * sizeScale), TextureFormat.RGB24, true);  
 
        for (int i = 0; i < sourcetex.width; ++i)  
            for (int j = 0; j < sourcetex.height; ++j)  
        {  
            Color color = sourcetex.GetPixel(i, j);  
            Color rgbColor = color;  
            Color alphaColor = color;  
            alphaColor.r = color.a;  
            alphaColor.g = color.a;  
            alphaColor.b = color.a;  
            rgbTex.SetPixel(i, j, rgbColor);  
            alphaTex.SetPixel((int)(i * sizeScale), (int)(j * sizeScale), alphaColor);  
        }  
 
        rgbTex.Apply();  
        alphaTex.Apply();  
 
        byte[] bytes = rgbTex.EncodeToPNG();  
        File.WriteAllBytes(GetRGBTexPath(_texPath), bytes);  
        bytes = alphaTex.EncodeToPNG();  
        File.WriteAllBytes(GetAlphaTexPath(_texPath), bytes);  
        Debug.Log("Succeed to seperate RGB and Alpha channel for texture : " + assetRelativePath);  
        AssetDatabase.Refresh();
    }  
 
    static bool HasAlphaChannel(Texture2D _tex)  
    {  
        for (int i = 0; i < _tex.width; ++i)  
            for (int j = 0; j < _tex.height; ++j)  
        {  
            Color color = _tex.GetPixel(i, j);  
            float alpha = color.a;  
            if (alpha < 1.0f - 0.001f)  
            {  
                return true;  
            }  
        }  
        return false;  
    }  
 
    static void SetTextureReadable(string _relativeAssetPath)  
    {  
        string postfix = GetFilePostfix(_relativeAssetPath);  
        if (postfix == ".dds")    // no need to set .dds file.  Using TextureImporter to .dds file would get casting type error.  
        {  
            return;  
        }  
 
        TextureImporter ti = (TextureImporter)TextureImporter.GetAtPath(_relativeAssetPath);  
        ti.isReadable = true;  
        AssetDatabase.ImportAsset(_relativeAssetPath);  
    }  
 
    #endregion  
 
 
    #region string or path helper  
 
    static bool IsTextureFile(string _path)  
    {  
        string path = _path.ToLower();  
        return path.EndsWith(".psd") || path.EndsWith(".tga") || path.EndsWith(".png") || path.EndsWith(".jpg") || path.EndsWith(".dds") || path.EndsWith(".bmp") || path.EndsWith(".tif") || path.EndsWith(".gif");  
    }  
 
    static string GetRGBTexPath(string _texPath)  
    {  
        return GetTexPath(_texPath, "_RGB.");  
    }  
 
    static string GetAlphaTexPath(string _texPath)  
    {  
        return GetTexPath(_texPath, "_Alpha.");  
    }  
 
    static string GetTexPath(string _texPath, string _texRole)  
    {  
        string result = _texPath.Replace(".", _texRole);  
        string postfix = GetFilePostfix(_texPath);  
        return result.Replace(postfix, ".png");  
    }  
 
    static string GetRelativeAssetPath(string _fullPath)  
    {  
        _fullPath = GetRightFormatPath(_fullPath);  
        int idx = _fullPath.IndexOf("Assets");  
        string assetRelativePath = _fullPath.Substring(idx);  
        return assetRelativePath;  
    }  
 
    static string GetRightFormatPath(string _path)  
    {  
        return _path.Replace("\\", "/");  
    }  
 
    static string GetFilePostfix(string _filepath)   //including '.' eg ".tga", ".dds"  
    {  
        string postfix = "";  
        int idx = _filepath.LastIndexOf('.');  
        if (idx > 0 && idx < _filepath.Length)  
            postfix = _filepath.Substring(idx, _filepath.Length - idx);  
        return postfix;  
    }  
 
    #endregion     
}

 

UGUI也是有辦法的,去官網下載Unity內置Shader,下當前最新版本
http://unity3d.com/cn/get-unity/download/archive
里面有Image用的默認Shader:Sprites-Default
再這個shader里面加點東西,就是alpha值從alpha_tex上獲取,rgb從rgb_tex上獲取。其實是一樣的。

 

注意點:
圖片最好2的冪次
Read/Write Enabled 不勾
Generate Mip Maps 不勾
512×512的紋理對於顯示效果已經夠用,那么就不要使用1024×1024的紋理

參考:
http://www.manew.com/thread-49730-1-1.html?_dsign=9e029b68 手機游戲開發中如何選擇適合的紋理格式
http://mp.weixin.qq.com/s?__biz=MzA4MDc5OTg5MA==&mid=209776006&idx=2&sn=d56d0bf4819493fa4fc452e36042890f&scene=5#rd Unity性能優化專題—騰訊牛人分享經驗
http://blog.uwa4d.com/archives/optimzation_memory_1.html 性能優化,進無止境-內存篇(上)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM