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 Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
} Cull Off
Lighting Off
ZWrite Off
Fog { Mode Off }
Offset -, -
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 Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
} Pass
{
Cull Off
Lighting Off
ZWrite Off
Fog { Mode Off }
Offset -, -
ColorMask RGB
AlphaTest Greater .
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 = ; i < sourcetex.width; ++i)
for (int j = ; 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 = ; i < _tex.width; ++i)
for (int j = ; 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 > && 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 性能优化,进无止境-内存篇(上)
- 本文固定链接: http://www.shihuanjue.com/?p=326
- 转载请注明: 乔 2016年05月05日 于 是幻觉 发表
Unity内存优化(贴图层面)的更多相关文章
- Unity内存优化
[Unity内存优化] 1.在Update方法或循环中,少用string类,因为string类的每次操作都会调用new生成新字符串对象.用StringBuilder代替string,StringBui ...
- Unity内存优化技术测试案例
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...
- Unity内存优化之视频讲解
视频为中文讲解,mp4格式,大小3.05GB 目录 扫码时备注或说明中留下邮箱 付款后如未回复请至https://shop135452397.taobao.com/ 联系店主
- Unity堆内存优化
unity中减少堆内存分配以减少垃圾回收处理:只有局部变量且为值类值的变量是从stack栈中分配内存,其它所有情况都是从heap堆中分配内在.* 缓存获取到的数据.* 频繁被调用的函数中尽量少的分配空 ...
- Unity性能优化专题---腾讯牛人分享经验
这里从三个纬度来分享下内存的优化经验:代码层面.贴图层面.框架设计层面. 一.代码层面. 1.foreach. Mono下的foreach使用需谨慎.频繁调用容易触及堆上限,导致GC过早触发,出现卡顿 ...
- Unity 性能优化(力荐)
开始之前先分享几款性能优化的插件: 1.SimpleLOD : 除了同样拥有Mesh Baker所具有的Mesh合并.Atlas烘焙等功能,它还能提供Mesh的简化,并对动态蒙皮网格进行了很好的支持. ...
- Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译
本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
- Unity内存理解(转)
Unity3D 里有两种动态加载机制:一个是Resources.Load,另外一个通过AssetBundle,其实两者区别不大. Resources.Load就是从一个缺省打进程序包里的AssetBu ...
- Unity3D 游戏开发之内存优化
项目的性能优化主要围绕CPU.GPU和内存三大方面进行. 无论是游戏还是VR应用,内存管理都是其研发阶段的重中之重. 然而,在我们测评过的大量项目中,90%以上的项目都存在不同程度的内存使用问题.就目 ...
随机推荐
- 【Python文件处理】递归批处理文件夹子目录内所有txt数据
因为有个需求,需要处理文件夹内所有txt文件,将txt里面的数据筛选,重新存储. 虽然手工可以做,但想到了python一直主张的是自动化测试,就想试着写一个自动化处理数据的程序. 一.分析数据格式 需 ...
- CF576E
*在#里发他一直WA这道CF题,然后我就去看了看,感觉还挺有趣的,那我就在这里整理一下我的思路..毕竟一边听歌.. 题意: 给个图,每条边初始无色,每次给一个询问(e,c)表示把e涂成颜色c,如果此时 ...
- MySQL详解--锁
http://blog.csdn.net/xifeijian/article/details/20313977 2014-03-06 23:45 66484人阅读 评论(17) 收藏 举报 分类: ...
- highcharts使用笔记
1.legend取消点击事件: 饼图:plotOptions.pie.point.events.legendItemClick = function() {return false;} 其他,如:pl ...
- ORACLE发送带附件邮件的二三事之一
在oracle使用过程中,我们可以通过pl/sql生成数据文件,也可以通过spool on spool off生成,但某些环境下,我们需要通过存储过程处理数据,数据处理完,需要自动生成数据文件,手工导 ...
- javascript的一些知识
一.Js的this,{},[] this是Javascript语言的一个关键字,随着函数使用场合的不同,this的值会发生变化.但是有一个总的原则,那就是this指的是调用的函数自己. { } 大括号 ...
- APM程序分析-ArduCopter.cpp
该文件是APM的主文件. #define SCHED_TASK(func, rate_hz, max_time_micros) SCHED_TASK_CLASS(Copter, &copter ...
- java注解处理
1.自定义注解类型 package com.yc.annotation; import java.lang.annotation.ElementType; import java.lang.ann ...
- 分享一个常用Adb命令
分享一个常用Adb命令 首先 首先感谢@xuxu的常用adb命令,收益良多,但是已经不能满足于我,所以补充了下. 再者 好久没发帖了,最近论坛老司机们都在讨论/总结,我就用这个干货回报吧. 最后 基于 ...
- linux学习日记之鸟哥
2016年10月11日星期二 df命令解释:用于显示磁盘分区上可以使用的磁盘空间.默认显示单位为KB,可以用该命令来获取硬盘被占用了多少空间,目前还剩多少空间等信息.用法:df 选项 参数例:df – ...