zoukankan      html  css  js  c++  java
  • 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 性能优化,进无止境-内存篇(上)

  • 相关阅读:
    JS日期格式转换
    VMware虚拟化集群的配置(一)
    网络初级篇之STP(概念原理)
    运维学习篇之jenkins的安装(CentOS7)
    网络初级篇之配置telnet登录网络设备(实验)
    Linux操作篇之OpenKM的安装(汉化)
    网络初级篇之网络设备的FTP(原理与实验)
    网络初级篇之直连路由与静态路由(原理与实验)
    网络初级篇之DHCP原理与配置(原理与实验)
    网络初级篇之OSPF(二)实验
  • 原文地址:https://www.cnblogs.com/joeshifu/p/5489906.html
Copyright © 2011-2022 走看看