整理资源的时候 发现材质属性面板上只有四张贴图 但是材质球确有五张贴图的依赖 想着写个工具处理下 没想到网上一搜已经有小哥写好了工具 直接拿来用了
代码上做了简洁
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System;
using UnityEngine;
using UnityEditor;
/// <summary>
/// 如果材质使用了带有两张贴图的Shader 并且对贴图赋了值
/// 再切换到带有一张贴图的Shader 此时就会有一张冗余贴图在材质中
/// 浪费内存 浪费加载带宽
/// </summary>
static class MaterialCleanerTools
{
[UnityEditor.MenuItem("Assets/Tools/清理材质无用贴图")]
public static void ClearMaterial()
{
UnityEngine.Object[] objects = Selection.GetFiltered(typeof(object), SelectionMode.Assets);
if (objects.Length == 0)
{
Debug.LogWarning("请选择资源目录后再进行操作");
return;
}
foreach (var obj in objects)
{
float index = 0;
string assetPath = AssetDatabase.GetAssetPath(obj);
string projectPath = Application.dataPath.Replace("Assets", "");
string fullPath = EditorPathUtils.ToUnixPath(projectPath + assetPath);
List<string> filePaths = EditorUtils.CollectFilesByEnd(fullPath, ".mat");
foreach (string filePath in filePaths)
{
string fileAssetPath = filePath.Replace(Application.dataPath, "Assets");
ClearMaterialAsset(fileAssetPath);
index++;
EditorUtility.DisplayProgressBar("清理材质无用的缓存属性", fileAssetPath, index / (float)filePaths.Count);
}
}
EditorUtility.ClearProgressBar();
}
public static void ClearMaterialAsset(string path)
{
if (String.IsNullOrEmpty(path))
{
return;
}
Material m = AssetDatabase.LoadAssetAtPath<Material>(path);
if (m == null)
return;
var deps = AssetDatabase.GetDependencies(new String[] { path });
var deps_textures = deps.Where(s => IsTextureAsset(s)).ToList();
var used_textures = new HashSet<String>();
var shader = m.shader;
var newMat = new Material(shader);
var c = ShaderUtil.GetPropertyCount(shader);
for (int i = 0; i < c; ++i)
{
var type = ShaderUtil.GetPropertyType(shader, i);
var name = ShaderUtil.GetPropertyName(shader, i);
var value = m.GetProperty(i);
switch (type)
{
case ShaderUtil.ShaderPropertyType.Color:
{
newMat.SetColor(name, m.GetColor(name));
}
break;
case ShaderUtil.ShaderPropertyType.Float:
{
newMat.SetFloat(name, m.GetFloat(name));
}
break;
case ShaderUtil.ShaderPropertyType.Range:
{
newMat.SetFloat(name, (float)value);
}
break;
case ShaderUtil.ShaderPropertyType.TexEnv:
{
newMat.SetTexture(name, (Texture)value);
newMat.SetTextureOffset(name, m.GetTextureOffset(name));
newMat.SetTextureScale(name, m.GetTextureScale(name));
var tpath = AssetDatabase.GetAssetPath((Texture)value);
if (!String.IsNullOrEmpty(tpath))
{
used_textures.Add(tpath);
}
}
break;
case ShaderUtil.ShaderPropertyType.Vector:
{
newMat.SetVector(name, (Vector4)value);
}
break;
}
}
bool rebuild = false;
if (used_textures.Count != deps_textures.Count)
{
for (int i = 0; i < deps_textures.Count; ++i)
{
var _fn = deps_textures[i];
if (!used_textures.Contains(_fn))
{
rebuild = true;
UnityEngine.Debug.LogWarning(String.Format("unused texture: {0}", _fn));
}
}
}
if (!rebuild)
{
if (newMat != null)
{
UnityEngine.Object.DestroyImmediate(newMat);
}
return;
}
string basePath = Path.GetFullPath(path + "/../").Replace(Path.GetFullPath(Application.dataPath), "Assets");
string fn = Path.GetFileNameWithoutExtension(path);
string ext = Path.GetExtension(path);
//SplitFullFilename(path, out fn, out ext, out basePath);
var tempAssetPath = String.Format("{0}{1}_temp.{2}", basePath, fn, ext);
var _test = AssetDatabase.LoadAllAssetsAtPath(tempAssetPath);
if (_test != null)
{
AssetDatabase.DeleteAsset(tempAssetPath);
}
// create a new material to replace it latter
AssetDatabase.CreateAsset(newMat, tempAssetPath);
Resources.UnloadAsset(newMat);
var tempAssetDataPath = String.Format("{0}{1}_datatemp.bytes", basePath, fn, ext);
if (File.Exists(tempAssetPath))
{
// rename it to .bytes
File.Copy(tempAssetPath, tempAssetDataPath, true);
// delete temp material
AssetDatabase.DeleteAsset(tempAssetPath);
if (File.Exists(tempAssetDataPath))
{
// delete original material
File.Delete(path);
// replace original material with .bytes file
File.Copy(tempAssetDataPath, path, true);
// remove bytes file
File.Delete(tempAssetDataPath);
AssetDatabase.Refresh();
}
}
return;
}
static object GetProperty(this Material material, int index)
{
var name = ShaderUtil.GetPropertyName(material.shader, index);
var type = ShaderUtil.GetPropertyType(material.shader, index);
switch (type)
{
case ShaderUtil.ShaderPropertyType.Color:
return material.GetColor(name);
case ShaderUtil.ShaderPropertyType.Vector:
return material.GetVector(name);
case ShaderUtil.ShaderPropertyType.Range:
case ShaderUtil.ShaderPropertyType.Float:
return material.GetFloat(name);
case ShaderUtil.ShaderPropertyType.TexEnv:
return material.GetTexture(name);
}
return null;
}
static bool IsTextureAsset(String assetPath)
{
var ext = Path.GetExtension(assetPath).ToLower();
return ext == ".png" ||
ext == ".tga" ||
ext == ".jpg" ||
ext == ".bmp" ||
ext == ".psd" ||
ext == ".dds" ||
ext == ".exr";
}
}