决定纹理资源大小的因素主要有三种:分辨率、格式和Mipmap是否开启。
对于纹理资源的加载建议如下:
1、严格控制RGBA32和ARGB32纹理的使用,在保证视觉效果的前提下,尽可能采用“够用就好”的原则,降低纹理资源的分辨率,以及使用硬件支持的纹理格式。
2、在硬件格式(ETC、PVRTC)无法满足视觉效果时,RGBA16格式是一种较为理想的折中选择,既可以增加视觉效果,又可以保持较低的加载耗时。
3、严格检查纹理资源的Mipmap功能,特别注意UI纹理的Mipmap是否开启。有不少项目的UI纹理均开启了Mipmap功能,不仅造成了内存占用上的浪费,同时也增加了不小的加载时间。
4、ETC2对于支持OpenGL ES3.0的Android移动设备来说,是一个很好的处理半透明的纹理格式。但是,如果你的游戏需要在大量OpenGL ES2.0的设备上进行运行,那么我们不建议使用ETC2格式纹理。因为不仅会造成大量的内存占用(ETC2转成RGBA32),同时也增加一定的加载时间。下图为测试2中所用的测试纹理在三星S3和S4设备上加载性能表现。可以看出,在OpenGL ES2.0设备上,ETC2格式纹理的加载要明显高于ETC1格式,且略高于RGBA16格式纹理。因此,建议研发团队在项目中谨慎使用ETC2格式纹理。
文章 加载模块深度解析 对图片的使用格式的方法进行了详细描述
批量检测和修改纹理格式代码如下:
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.IO;
public partial class ResourceExporter
{
static List GetAllTex(bool bFilter, CheckPlatformTexFormat checkAndroid, CheckPlatformTexFormat checkIphone, ReplacePlatformTexFormat replaceAction = null)
{
List<string> texPathLs = new List<string>();
GetAssetsTexInSubFolderForAtlas("assets", ref texPathLs);
List infoLs = new List();
int totalCount = texPathLs.Count;
if (texPathLs.Count>0)
{
int iCurCount = 0;
foreach (var path in texPathLs)
{
TextureImporter texImporter = TextureImporter.GetAtPath(path) as TextureImporter;
if (null != texImporter)
{
TextureFormatInfo texFormatInfo = new TextureFormatInfo(texImporter.assetPath);
texImporter.GetPlatformTextureSettings("Standalone", out texFormatInfo.windowsMaxSize, out texFormatInfo.texFormatWindows);
texImporter.GetPlatformTextureSettings("iPhone", out texFormatInfo.iphoneMaxSize, out texFormatInfo.texFormatIphone);
texImporter.GetPlatformTextureSettings("Android", out texFormatInfo.androidMaxSize, out texFormatInfo.texFormatAndroid);
texFormatInfo.bMipMapEnabled = texImporter.mipmapEnabled;
bool bAdd = true;
texFormatInfo.bNeedAndroidFormat = checkAndroid(texFormatInfo.texFormatAndroid);
texFormatInfo.bNeedIphoneFormat = checkIphone(texFormatInfo.texFormatIphone);
if (bFilter)
{
bAdd = texFormatInfo.bMipMapEnabled || (!texFormatInfo.bNeedAndroidFormat) || (!texFormatInfo.bNeedIphoneFormat);
}
if (bAdd)
{
Debug.Log(texFormatInfo.ToString());
if (null != replaceAction)
{
replaceAction(texImporter,texFormatInfo);
}
infoLs.Add(texFormatInfo);
}
}
EditorUtility.DisplayCancelableProgressBar("Check TexFormat", "Wait......", (++iCurCount) * 1f / totalCount);
}
}
totalCount = infoLs.Count;
Debug.Log("PathCount:" + texPathLs.Count);
Debug.Log("InfoCount:" + infoLs.Count);
EditorUtility.ClearProgressBar();
return infoLs;
}
static void SaveTextureFormatInfoPath(List infoLs)
{
string fileSavePath = "../AllTextureFormatInfoPath";
int totalCount = infoLs.Count;
using (StreamWriter sw = File.CreateText(fileSavePath + ".html"))
{
sw.WriteLine("size = " + totalCount + "");
foreach (var info in infoLs)
{
sw.WriteLine(info.ToHtmlString());
}
sw.Close();
}
}
static bool CheckAndroidFormat(TextureImporterFormat format)
{
return format == TextureImporterFormat.ETC_RGB4;
}
static bool CheckIphoneFormat(TextureImporterFormat format)
{
return format.ToString().Contains("PVRTC");
}
delegate bool CheckPlatformTexFormat(TextureImporterFormat format);
delegate void ReplacePlatformTexFormat(TextureImporter textureImporter,TextureFormatInfo texInfo);
static void ReplacePlatformFormat(TextureImporter textureImporter, TextureFormatInfo texInfo)
{
textureImporter.mipmapEnabled = false;
textureImporter.SetPlatformTextureSettings("Android", texInfo.androidMaxSize, TextureImporterFormat.ETC_RGB4);
AssetDatabase.ImportAsset(textureImporter.assetPath);
}
class TextureFormatInfo
{
public string path;
public bool bMipMapEnabled;
public bool bNeedAndroidFormat;
public bool bNeedIphoneFormat;
public TextureImporterFormat texFormatIphone;
public TextureImporterFormat texFormatAndroid;
public TextureImporterFormat texFormatWindows;
public int androidMaxSize;
public int iphoneMaxSize;
public int windowsMaxSize;
public TextureFormatInfo(string filePath)
{
path = filePath;
}
public string ToString()
{
string strFormat = "{0}: MipMapEnabled:{1},\nAndroid:{2},\nIphone:{3}";
return string.Format(strFormat, path, bMipMapEnabled, texFormatAndroid, texFormatIphone, texFormatWindows);
}
public string ToHtmlString()
{
// size = 2357
string strFormat = "{0}:         {1},        {2},         {3}";
string bMipStr = string.Format("MipMapEnabled:{0}", bMipMapEnabled);
string parm1 = bMipMapEnabled ? GetSpecialTip(bMipStr, "red") : bMipStr;
string androidStr = string.Format("Android:{0}", texFormatAndroid);
string parm2 = !bNeedAndroidFormat ? GetSpecialTip(androidStr, "blue") : androidStr;
string iphoneStr = string.Format("Iphone:{0}", texFormatIphone);
string parm3 = !bNeedIphoneFormat ? GetSpecialTip(iphoneStr, "YellowGreen") : iphoneStr;
return string.Format(strFormat, path, parm1, parm2, parm3);
}
private string GetSpecialTip(string name,string fontColor)
{
return string.Format("{1}", fontColor, name);
}
}
static void GetAssetsTexInSubFolderForAtlas(string srcFolder, ref List<string> atlas)
{
string searchPattern0 = "*.png";
string searchPattern1 = "*.tga";
string searchPattern2 = "*.psd";
string searchFolder = srcFolder.Replace(@"\", @"/");
string searchDir0 = searchFolder;
if (Directory.Exists(searchDir0))
{
//string[] files = Directory.GetFiles(searchDir0, searchPattern);
AddFilePathToList(Directory.GetFiles(searchDir0, searchPattern0), ref atlas);
AddFilePathToList(Directory.GetFiles(searchDir0, searchPattern1),ref atlas);
AddFilePathToList(Directory.GetFiles(searchDir0, searchPattern2),ref atlas);
}
string[] dirs = Directory.GetDirectories(searchFolder);
foreach (string oneDir in dirs)
{
GetAssetsTexInSubFolderForAtlas(oneDir, ref atlas);
}
}
static void AddFilePathToList(string[] files, ref List<string> ls)
{
foreach (string oneFile in files)
{
string srcFile = oneFile.Replace(@"\", @"/");
string lowerFile = srcFile.ToLower();
ls.Add(lowerFile);
}
}
[MenuItem("MyEditor/Check Texture Format")]
public static void CheckTextureFormat()
{
List infoLs = GetAllTex(true, CheckAndroidFormat, CheckIphoneFormat);
SaveTextureFormatInfoPath(infoLs);
}
[MenuItem("MyEditor/Replace Texture Format")]
public static void ReplaceTextureFormat()
{
GetAllTex(true, CheckAndroidFormat, CheckIphoneFormat, ReplacePlatformFormat);
//SaveTextureFormatInfoPath(infoLs);
}
}