最近在做Unity转微信小游戏的工作,微信小游戏对包体大小优化要求较高,而纹理图片资源向来是包体大小占用的大头,本篇记录一下批量压缩纹理资源的工具。
Unity各平台支持的纹理压缩格式
Unity2021开始支持ASTC压缩格式,因此针对微信小游戏最好使用Unity2021及以上版本能得到最好的纹理压缩支持。
using System;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityEditor;
public class SpriteImporter : AssetPostprocessor
{
[MenuItem("Assets/Custom Reimport Images")]
static void SetAllTextureType()
{
//获取鼠标点击目录
var arr = Selection.GetFiltered(typeof(DefaultAsset), SelectionMode.Assets);
string folder = AssetDatabase.GetAssetPath(arr[0]);
Debug.Log($"Reimport Path: {
folder}");
DirectoryInfo direction = new DirectoryInfo(folder);
FileInfo[] pngFiles = direction.GetFiles("*.png", SearchOption.AllDirectories);
FileInfo[] jpgFiles = direction.GetFiles("*.jpg", SearchOption.AllDirectories);
try
{
SetTexture(pngFiles);
SetTexture(jpgFiles);
}
catch (Exception e)
{
Debug.Log(e);
throw;
}
finally
{
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
}
}
private static void SetTexture(FileInfo[] files)
{
for (int i = 0; i < files.Length; i++)
{
//返回绝对路径
string fullPath = files[i].FullName.Replace("\\", "/");
//Debug.Log($"Set {fullPath}");
//通过替换Application.dataPath为Assets变为相对路径
string path = fullPath.Replace(Application.dataPath, "Assets");
TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
EditorUtility.DisplayProgressBar("批量处理图片",files[i].Name,i/(float)files.Length);
SetTextureFormat(textureImporter);
}
}
private static void SetTextureFormat(TextureImporter textureImporter)
{
textureImporter.mipmapEnabled = false;
textureImporter.isReadable = false;
int maxSize = GetMaxSize(textureImporter);
TextureImporterFormat defaultAlpha;
TextureImporterFormat defaultNoAlpha;
//这里设置要放在对应的平台代码块内,否则改变的就是默认的平台
#if UNITY_ANDROID
TextureImporterPlatformSettings settings_Android = new TextureImporterPlatformSettings();
//标识平台为Android 大小写都可以
settings_Android.name = "Android";
settings_Android.overridden = true;
settings_Android.maxTextureSize = maxSize;
bool divisibleOf4 = IsDivisibleOf4(textureImporter);
defaultAlpha = divisibleOf4 ? TextureImporterFormat.ETC2_RGBA8 : TextureImporterFormat.ASTC_4x4;
defaultNoAlpha = divisibleOf4 ? TextureImporterFormat.ETC2_RGB4 : TextureImporterFormat.ASTC_4x4;
settings_Android.format = textureImporter.DoesSourceTextureHaveAlpha() ? defaultAlpha : defaultNoAlpha;
textureImporter.SetPlatformTextureSettings(settings_Android);
#elif UNITY_IOS
TextureImporterPlatformSettings settings_IOS = new TextureImporterPlatformSettings();
settings_IOS.name = "IOS";
settings_IOS.overridden = true;
settings_IOS.maxTextureSize = maxSize / 4;
bool powerOfTwo = IsPowerOfTwo(textureImporter);
defaultAlpha = powerOfTwo ? TextureImporterFormat.PVRTC_RGBA4 : TextureImporterFormat.ASTC_4x4;
defaultNoAlpha = powerOfTwo ? TextureImporterFormat.PVRTC_RGB4 : TextureImporterFormat.ASTC_4x4;
settings_IOS.format = textureImporter.DoesSourceTextureHaveAlpha() ? defaultAlpha : defaultNoAlpha;
textureImporter.SetPlatformTextureSettings(settings_IOS);
#elif UNITY_WEBGL
TextureImporterPlatformSettings settings_WebGl = new TextureImporterPlatformSettings();
settings_WebGl.name = "WebGL";
settings_WebGl.overridden = true;
settings_WebGl.maxTextureSize = (maxSize / 4) <= 32 ? 32 : maxSize / 4;
bool divisibleOf4 = IsDivisibleOf4(textureImporter);
defaultAlpha = divisibleOf4 ? TextureImporterFormat.DXT5Crunched : TextureImporterFormat.ASTC_4x4;
defaultNoAlpha = divisibleOf4 ? TextureImporterFormat.DXT1Crunched : TextureImporterFormat.ASTC_4x4;
//defaultAlpha = TextureImporterFormat.ASTC_4x4;
//defaultNoAlpha = TextureImporterFormat.ASTC_4x4;
settings_WebGl.format = textureImporter.DoesSourceTextureHaveAlpha() ? defaultAlpha : defaultNoAlpha;
textureImporter.SetPlatformTextureSettings(settings_WebGl);
#elif UNITY_STANDALONE
#endif
//保存更改并重新导入图片
textureImporter.SaveAndReimport();
}
private static int[] sizes = {
32, 64, 128, 256, 512, 1024, 2048, 4096};
private static int GetMaxSize(TextureImporter textureImporter)
{
(int width, int height) = GetTextureImporterSize(textureImporter);
//Debug.Log($"width: {width} height: {height}");
int tempMax = Mathf.Max(height, width);
foreach (var size in sizes)
{
if (tempMax <= size)
return size;
}
return 2048;
}
//获取导入图片的宽高
static (int, int) GetTextureImporterSize(TextureImporter textureImporter)
{
if (textureImporter != null)
{
object[] args = new object[2];
MethodInfo mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Invoke(textureImporter, args);
return ((int)args[0], (int)args[1]);
}
return (0, 0);
}
//长宽都被4整除
static bool IsDivisibleOf4(TextureImporter textureImporter)
{
(int width, int height) = GetTextureImporterSize(textureImporter);
return (width % 4 == 0 && height % 4 == 0);
}
//2的整数次幂
static bool IsPowerOfTwo(TextureImporter textureImporter)
{
(int width, int height) = GetTextureImporterSize(textureImporter);
return (width == height) && (width > 0) && ((width & (width - 1)) == 0);
}
}