一 、事故描述
我有一个需求:在工程文件中找得到所有的图片(Texture 2D),然后把WebGL发布打包时的图片压缩规则进行修改。
项目中有图片2千多张,其中2k分辨率的图片上百张,当我右键进行批量处理的时候,内存蹭蹭蹭往上冒,直接吃满,然后显示Unity挂掉,接着其他程序也会挂,最后电脑卡住...
二、原因分析
当我全选整个项目中的图片,然后右键菜单执行该脚本后,它加载图片的代码如下:
csharp
Object[] textures = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets);
这个数组会爆仓内存。
其次:每张图单独处理的时候,我new了两个东西,如下
new的第一个组件
csharp
// 创建特定平台压缩实例
TextureImporterPlatformSettings platformSettings = new TextureImporterPlatformSettings();
//设置属性
new的第二个组件
csharp
//设置importSettings
TextureImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;
//设置属性
这两个组件是在一个for循环里面,用完之后,没有设置为null。
三、换种思路
- 1、只抓取资源id
csharp
string[] guids = AssetDatabase.FindAssets("t:texture2d");
- 2、用id取获取图片对象
csharp
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
- 3、new 出来的组件记得清空
csharp
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path) ;
TextureImporterPlatformSettings platformSettings = new TextureImporterPlatformSettings();
TextureImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;
//属性赋值
//.....
//-----------------清空对象-----------------至于什么时候触发GC,那就不知道了
platformSettings = null;
importer = null;
texture = null;
- 3、图片上的组件用完及时清空
csharp
static void FindAllTexture2D()
{
//****************************************参数设置区**********begin
//TODO 做成EditWindow类型
TextureImporterFormat format = TextureImporterFormat.ASTC_12x12; //图片压缩格式
int compressionQuality = 60; //压缩比例
string platform = "WebGL"; //发布的平台
//************************************************************end
//查找工程文件中的所有精灵图片
string[] guids = AssetDatabase.FindAssets("t:texture2d");
Debug.Log($"Found {guids.Length} Texture2d assets.");
foreach (string guid in guids)
{
try
{
string path = AssetDatabase.GUIDToAssetPath(guid);
Debug.Log($"{path}");
// 使用AssetDatabase加载Texture2D
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
//Debug.Log($"{texture.name}");
if (texture == null) continue;
// 创建特定平台压缩实例
TextureImporterPlatformSettings platformSettings = new TextureImporterPlatformSettings();
platformSettings.overridden = true;
platformSettings.name = platform;
// 设置为压缩
platformSettings.textureCompression = TextureImporterCompression.Compressed;
// 设置压缩格式
platformSettings.format = format; //TextureImporterFormat.ASTC_12x12;
platformSettings.compressionQuality = compressionQuality; //40
platformSettings.maxTextureSize = GetMaxSize(texture as Texture2D); //32
//设置importSettings
TextureImporter importer =
AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;
if (importer == null) continue;
importer.SetPlatformTextureSettings(platformSettings);
//Apply 设置
importer.SetPlatformTextureSettings(platformSettings);
//保存资源
importer.SaveAndReimport();
//资源清空
platformSettings = null;
importer = null;
texture = null;
}
catch (Exception ex)
{
Debug.Log( $" ~~~~~error~~~~~ 设置报错:{ex.Message}");
}
}
}
四、附录:出错的脚本
csharp
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
public class SetTextureCompression
{
//****************************************参数设置区**********begin
//TODO 做成EditWindow类型
private static TextureImporterFormat format = TextureImporterFormat.ASTC_12x12; //图片压缩格式
private static int compressionQuality = 60; //压缩比例
private static string platform = "WebGL"; //发布的平台
//************************************************************end
/// <summary>
/// 设置贴图在build时的压缩选项
/// </summary>
[MenuItem("Assets/设置发布WebGL时贴图的压缩格式")]
static void SetCompression()
{
int count = 0;
Object[] textures = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets);
if (textures.Length > 0)
{
foreach (Object texture in textures)
{
// 创建特定平台压缩实例
TextureImporterPlatformSettings platformSettings = new TextureImporterPlatformSettings();
platformSettings.overridden = true;
platformSettings.name = platform;
// 设置为压缩
platformSettings.textureCompression = TextureImporterCompression.Compressed;
// 设置压缩格式
platformSettings.format = format;
platformSettings.compressionQuality = compressionQuality;
platformSettings.maxTextureSize = GetMaxSize(texture as Texture2D);
//设置importSettings
TextureImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;
importer.SetPlatformTextureSettings(platformSettings);
//Apply 设置
importer.SetPlatformTextureSettings(platformSettings);
//保存资源
importer.SaveAndReimport();
count++;
}
//Debug.Log("Texture Compression Set!");
}
else
{
Debug.LogWarning("没有选中图片!");
}
Debug.Log($"一共处理了{count}张图片!");
}
/// <summary>
/// 获取图片的分辨率,取分辨率中高宽的最大值,然后返回图片的【MaxSize】
/// MaxSize的定义:assets->Image->【Texture2D ImportSettings】->【Override For WebGL】->【Max Size】
/// 区间:16,32,64,128,256,512,1024,2048,4096,8192,16384
///
/// 举例:图片分辨率 = 12 * 24,那么图片的MaxSize = 32
/// </summary>
/// <param name="texture"></param>
/// <returns></returns>
static int GetMaxSize(Texture2D texture)
{
//分辨率区间的预备
var start = new List<int> { 0, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
var end = new List<int> { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 100000 };
var zones = start.Zip(end, (item1, item2) => (startIdx: item1, endIdx: item2)).ToList();
//取分辨率高宽的最大值
var size = new List<int> { texture.width, texture.height }.Max(); //取【宽】【高】中的最大值
//判断所属的区间
var maxSize = zones
.First(x => x.startIdx <= size && size <= x.endIdx)
.endIdx;
//Debug.Log($"图的分辨率 = {texture.width} * {texture.height} size = {size}, MaxSize = {maxSize}");
return maxSize;
}
}