282 lines
11 KiB
C#
282 lines
11 KiB
C#
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|