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
}

注意点:
图片最好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 性能优化,进无止境-内存篇(上)

时间: 2024-10-09 10:02:20

Unity内存优化(贴图层面)的相关文章

Unity内存优化

对项目优化有很多,如:mesh合并,减少DrawCall和模型骨骼以及物理计算,合并材质球,优化代码等等. 优化: 1. 更新不透明贴图的压缩格式为ETC 4bit,因为android市场的手机中的GPU有多种,每家的GPU支持不同的压缩格式,但他们都兼容ETC格式. 2.对于透明贴图,我们只能选择RGBA 16bit 或者RGBA 32bit. 3.减少FPS 在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS

Unity内存优化技术测试案例

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解>电子工业出版社等. CSDN视频网址:http://edu.csdn.net/lecturer/144 Unity引擎优化技术,无非涉及到三点:CPU优化,GPU优化,内存优化. 先谈谈内存优化:大概可以分成三大部分: 1. Unity3D内部的内存 2. Mono的托管内存 3. 引入的DLL或者第

C# 与 Unity内存优化

转载自:http://www.xuanyusong.com/archives/1919 客户端与服务器的交互,使用JSON 和XML会感觉数据量太大,影响效率.使用二进制可以很大把空间节省. 在写入二进制数据时用到的核心类就是BinaryWriter ,Binary是二进制的意思 ,可见操作二进制写入就用BinaryWriter了. 常用的数据类型会分配固定的字节数量,假设BinaryWriter 写入一个short 那么就占2字节,写一个 int 就占4字节,如果是数组的话需要数组类型字节长度

Unity的内存优化方案 (转)

Unity3D占用内存太大的解决方法 最近网友通过网站搜索Unity3D在手机及其他平台下占用内存太大. 这里写下关于Unity3D对于内存的管理与优化. Unity3D 里有两种动态加载机制:一个是Resources.Load,另外一个通过AssetBundle,其实两者区别不大.Resources.Load就是从一个缺省打进程序包里的AssetBundle里加载资源,而一般AssetBundle文件需要你自己创建,运行时 动态加载,可以指定路径和来源的. 其实场景里所有静态的对象也有这么一个

Unity Mono运行机制分析及内存优化

一.Mono原理 此处简单介绍下Mono这个奇葩,主要通过Mono可以轻松实现跨平台,目前使用Unity开发手游Android平台大多使用Mono实现,但是诛仙手游使用il2cpp技术.具体il2cpp知识大家可以度娘. 二.内存分配机制 上图为内存分配策略,但是在此结合实践经验有bug存在,当分配大块内存特别明显,来回分配与切换应用会崩溃,主要是GC不够及时即使是每次分配完手动GC也不会立即释放. 三.内存泄漏原因 Mono是如何判断已用内存中哪些是不再需要使用的呢?是通过引用关系的方式来进行

unity profile使用,内存优化,包大小优化

游戏优化往往是游戏开发中比较重要的一个环节,下面就分享一些自己在性能优化,内存优化,包大小优化方面的经验和总结. Profiler 是unity自带的,用来分析游戏运行性能,内存使用等非常好的工具,你可以通过它准确定位到影响游戏性能的脚本方法,内存过高的资源等等,对你优化游戏性能,内存有很大的帮助. 一.cpu占用分析 可以看出在白色竖线定位的那一帧,Game.Update()占用了88.3%,如果想知道脚本具体调用堆栈,和具体的问题出在哪,需要把Deep Profiler选上进行深度分析,当你

Unity性能优化专题—腾讯牛人分享经验 (难度1 推荐3)

原文地址: 腾讯游戏开发者平台 之前因为老大要求,要把unity最终发布的包压缩到至少之前大小的一半,这可难倒我了,不过最终还是在问了很多大神后解决了,主要是在本文章中讲的"二". tag: unity素材压缩.unity资源压缩.unity压缩包大小.unity怎么节省空间 这里从三个纬度来分享下内存的优化经验:代码层面.贴图层面.框架设计层面. 一.代码层面. 1.foreach. Mono下的foreach使用需谨慎.频繁调用容易触及堆上限,导致GC过早触发,出现卡顿现象. 特别

Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻译 Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译 Unity性能优化(3)-官方教程Optimizing garbage collection in Uni

U3D内存优化

原创文章如需转载请注明:转载自风宇冲Unity3D教程学院  U3D内存优化 读了Hog关于内存管理文章, 自己测试了下. 有以下收获: (1)Unity的Profiler性能监测是非常准确. (2)测试复盘的 结果也完全与Hog的一致 (3)但是场景里已经放的物体,删除后,GameObject,Transform等复制出来的是被删掉了.但是引用的贴图却没有被删除.使用Resources.UnloadUnusedAssets并没有效果. 或者实时创建的,依然没有被释放. 最后用了Resource