Files
JJBB/Assets/Editor/Scripts/TextureUtility/TextureUtility.cs

282 lines
11 KiB
C#
Raw Permalink Normal View History

2024-08-23 15:49:34 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using BundleV2;
using UnityEditor;
using UnityEngine;
public static class TextureUtility
{
public const string t4MControlTextureHeader = "Assets/T4MOBJ/Terrains/Texture/";
public const string postProcessTextureHeader = "Assets/Plugins/PostProcessing/";
[MenuItem("ProTool/PurgeAssets/Reimport All Sprites", false, 5)]
public static void ReimportAllSprites()
{
var action = new ReimportSpriteAction(GetAllTexturePaths());
action.Start();
}
[MenuItem("ProTool/PurgeAssets/Get All Non Power2", false, 5)]
public static void GetAllNonPower2()
{
var action = new GetAllNonPowerAction(GetAllTexturePaths());
action.Start();
}
private static HashSet<string> GetNonCompressTextures()
{
// 特殊处理T4M相关的法线贴图
var materials = (from assetPath in AssetDatabase.GetAllAssetPaths()
where assetPath.StartsWith("Assets/")
where ".mat" == Path.GetExtension(assetPath)
let material = AssetDatabase.LoadAssetAtPath<Material>(assetPath)
where material && material.shader
let shaderName = material.shader.name
where shaderName.Contains("/T4M", StringComparison.OrdinalIgnoreCase) ||
shaderName.Contains("/T3M", StringComparison.OrdinalIgnoreCase) ||
shaderName.Contains("/T2M", StringComparison.OrdinalIgnoreCase)
select assetPath).ToArray();
var hashSet = new HashSet<string>();
for (var i = 0; i < materials.Length; i++)
{
EditorUtility.DisplayProgressBar("Collect Textures", string.Format("({0} / {1})", i, materials.Length),
(float) i / materials.Length);
var dependencies = AssetDatabase.GetDependencies(materials[i], true);
foreach (var dependency in dependencies)
if (EditorAssetConst.textureExtensions.Contains(Path.GetExtension(dependency)))
hashSet.Add(dependency);
}
var normals = hashSet.ToArray();
// 重新装入保护系统
hashSet.Clear();
for (var i = 0; i < normals.Length; i++)
{
EditorUtility.DisplayProgressBar("Get T4M Normals", string.Format("({0} / {1})", i, normals.Length),
(float) i / normals.Length);
var textureImporter = AssetImporter.GetAtPath(normals[i]) as TextureImporter;
if (textureImporter && textureImporter.textureType == TextureImporterType.NormalMap)
hashSet.Add(normals[i]);
}
EditorUtility.ClearProgressBar();
// 特殊处理T4M的控制贴图
var controls = from assetPath in AssetDatabase.GetAllAssetPaths()
where assetPath.StartsWith(t4MControlTextureHeader) || assetPath.StartsWith(postProcessTextureHeader)
where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
select assetPath;
foreach (var control in controls)
hashSet.Add(control);
return hashSet;
}
private static void SetIosCompression(TextureImporter importer, bool isCompress)
{
var platformSetting = importer.GetPlatformTextureSettings("iPhone");
if (isCompress)
{
platformSetting.overridden = true;
platformSetting.textureCompression = TextureImporterCompression.Compressed;
platformSetting.crunchedCompression = true;
var useRgba = importer.textureCompression.ToString().StartsWith("RGBA", StringComparison.OrdinalIgnoreCase);
platformSetting.format = useRgba ? TextureImporterFormat.ETC2_RGBA8Crunched : TextureImporterFormat.ETC_RGB4Crunched;
}
else
platformSetting.overridden = false;
}
[MenuItem("Bundle V2/Purge/Set All IPhone Textures")]
public static void SetAllIPhoneTextures()
{
var importers = (from assetPath in AssetDatabase.GetAllAssetPaths()
where assetPath.StartsWith(AssetConst.nonInternalHeader)
where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
let importer = AssetImporter.GetAtPath(assetPath) as TextureImporter
where importer
select importer).ToArray();
for (var i = 0; i < importers.Length; i++)
{
EditorUtility.DisplayProgressBar("配置苹果压缩格式",
string.Format("{0} / {1}", i + 1, importers.Length),
(float)i / importers.Length);
var importer = importers[i];
var platformSetting = importer.GetPlatformTextureSettings("iPhone");
if (importer.textureCompression != TextureImporterCompression.Uncompressed &&
importer.textureType == TextureImporterType.Sprite)
{
platformSetting.overridden = true;
platformSetting.textureCompression = TextureImporterCompression.Compressed;
platformSetting.crunchedCompression = true;
platformSetting.format = TextureImporterFormat.ETC2_RGBA8Crunched;
}
else
{
platformSetting.overridden = false;
}
importer.SetPlatformTextureSettings(platformSetting);
importer.SaveAndReimport();
}
}
[MenuItem("Bundle V2/Purge/Texture Compress")]
public static void PurgeCompression()
{
var nonCompress = GetNonCompressTextures();
var allTextures = (from assetPath in AssetDatabase.GetAllAssetPaths()
where assetPath.StartsWith("Assets/")
where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
select assetPath).ToArray();
for (var i = 0; i < allTextures.Length; i++)
{
var texture = allTextures[i];
EditorUtility.DisplayProgressBar("Check Texture", string.Format("({0} / {1})", i, allTextures.Length),
(float) i / allTextures.Length);
var importer = AssetImporter.GetAtPath(texture) as TextureImporter;
if (importer)
{
var dirty = false;
var compress = nonCompress.Contains(texture)
? TextureImporterCompression.Uncompressed
: TextureImporterCompression.Compressed;
if (compress != importer.textureCompression)
{
dirty = true;
importer.textureCompression = compress;
SetIosCompression(importer, compress != TextureImporterCompression.Uncompressed);
}
if (compress == TextureImporterCompression.Compressed && !importer.crunchedCompression)
{
dirty = true;
importer.crunchedCompression = true;
}
if (importer.textureType == TextureImporterType.Sprite && importer.mipmapEnabled)
{
dirty = true;
importer.mipmapEnabled = false;
}
if (dirty)
importer.SaveAndReimport();
}
}
EditorUtility.ClearProgressBar();
}
private static string[] GetAllTexturePaths()
{
var assetPaths = from assetPath in AssetDatabase.GetAllAssetPaths()
where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
select assetPath;
return assetPaths.ToArray();
}
private class ReimportSpriteAction : EditorPerFrameActionBase
{
private readonly string[] _assetPaths;
private int _index;
public ReimportSpriteAction(string[] assetPaths)
{
_assetPaths = assetPaths;
}
protected override int GetTotalCount()
{
return _assetPaths.Length;
}
protected override int GetCurrentIndex()
{
return _index;
}
protected override void PerFrameAction()
{
var assetPath = _assetPaths[_index];
var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
if (importer != null && importer.textureType == TextureImporterType.Sprite)
importer.SaveAndReimport();
_index++;
}
}
private class GetAllNonPowerAction : EditorPerFrameActionBase
{
private const string _filePath = "Assets/_Test/NonPower2Textures.txt";
private readonly string[] _assetPaths;
private readonly StringBuilder _builder;
private int _index;
public GetAllNonPowerAction(string[] assetPaths)
{
_assetPaths = assetPaths;
_builder = new StringBuilder();
}
protected override int GetTotalCount()
{
return _assetPaths.Length;
}
protected override int GetCurrentIndex()
{
return _index;
}
protected override void PerFrameAction()
{
var assetPath = _assetPaths[_index];
var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
if (importer != null && importer.textureType != TextureImporterType.Sprite)
{
var args = new object[2];
var mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight",
BindingFlags.NonPublic | BindingFlags.Instance);
if (mi != null)
mi.Invoke(importer, args);
if (args[0] == null || args[1] == null)
{
Debug.LogError("无法获得贴图尺寸,于" + importer.assetPath);
_builder.AppendLine(importer.assetPath + "; 尺寸无法获得!");
}
else
{
var width = (int) args[0];
var height = (int) args[1];
if (!IsPowerOf2(width) || !IsPowerOf2(height))
_builder.AppendLine(importer.assetPath +
string.Format("; 尺寸 {0} x {1} 不是2的次方", width, height));
}
}
_index++;
}
protected override void OnFinish()
{
base.OnFinish();
var filePath = Application.dataPath.MoveUp().Open(_filePath);
File.WriteAllText(filePath, _builder.ToString());
Debug.LogWarning("贴图尺寸扫描结果已输出到 " + filePath);
}
private static bool IsPowerOf2(int number)
{
// 如果小于等于1
if (number < 2) return false;
// 或者二进制中1的位数超过1位即不是二的次方
int count;
for (count = 0; count < number; count++)
number &= number - 1; // 清除最低位的1
return count < 2;
}
}
}