/******************************************************************************
* DESCRIPTION: 清理未使用的shader
* CREATED: 2020.09.24
* shader在绝大多数情况下,会在以下几种情况里附加上资源:
1. 最常见的,使用了shader的material
2. 比较常见的,cs脚本里直接用Shader.Find(shaderName)进行动态加载shader
3. 这个shader拖给脚本上的public shader,脚本挂在场景里的物体上
4. 这个shader拖给脚本上的public shader,脚本挂在prefab的物体上
5. 这个shader托给了ScriptableObject类的asset资源上
6. 剩下的小部分情况,比如script上的default reference基本不使用,就不做考虑
*******************************************************************************/
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
public class CleanUselessShader: Editor
{
[MenuItem("Tools/Clean Useless Shader", priority = 10)]
public static void CleanUnuseShader()
{
//先把当前场景和资源的修改保存,以免遗漏或误删
EditorSceneManager.SaveOpenScenes();
AssetDatabase.SaveAssets();
//拿到所有shader文件的guid,并在材质、场景、cs脚本、prefab文件、asset文件的文本里搜寻该guid
string[] shaderGUIDs = AssetDatabase.FindAssets("t:Shader");
string[] checkTypes = { "*.mat", "*.unity", "*.cs", "*.prefab", "*.asset" };
for (int i = 0; i < shaderGUIDs.Length; i++)
{
bool shaderIsUseless = true;
//shaderName不是shader文件名,而是shader的代码第一句Shader后的索引名
string shaderName = GUIDToShaderName(shaderGUIDs[i]);
for (int j = 0; j < checkTypes.Length; j++)
{
shaderIsUseless &= CheckShaderUseless(checkTypes[j], shaderGUIDs[i], shaderName);
//发现该shader还在使用就不用继续查了
if (!shaderIsUseless) break;
}
if (shaderIsUseless)
{
//把没用的shader删掉
AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(shaderGUIDs[i]));
Debug.LogFormat("Delete useless shader {0}", shaderName);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
///
/// 检查一个shader是否无用
///
///
///
///
///
private static bool CheckShaderUseless(string checkType, string shaderGUID = null, string shaderName = null)
{
bool useless = true;
string pattern = null;
//scene/prefab/material/asset都是序列文本文件,直接读取文本搜索guid即可
//cs脚本里对shader的使用,是用shaderName进行Find,所以不用guid而是shaderName作为pattern
//检查除cs脚本以外的shader使用情况
if (shaderGUID != null && checkType != "*.cs")
{
if (shaderName == null)
shaderName = GUIDToShaderName(shaderGUID);
pattern = shaderGUID;
}//检查cs脚本里shader使用情况(一般直接用shaderName搜索【非shader文件名】)
else if (shaderName != null && checkType == "*.cs")
{
pattern = shaderName;
}
else
{
return useless;
}
List paths = new List(Directory.GetFiles("Assets/", checkType, SearchOption.AllDirectories));
for (int i = 0; i < paths.Count; i++)
{
if (Regex.IsMatch(File.ReadAllText(paths[i]), pattern))
{
useless = false;
break;
}
if (EditorUtility.DisplayCancelableProgressBar
("Clean shader " + shaderName + "...", "Check :" + Path.GetFileName(paths[i]), (float)i / (paths.Count - 1)))
{
break;
}
if (i == paths.Count - 1)
EditorUtility.ClearProgressBar();
}
return useless;
}
private static string GUIDToShaderName(string shaderGUID)
{
string path = AssetDatabase.GUIDToAssetPath(shaderGUID);
string shaderName = null;
if (path != null)
{
Shader shader = AssetDatabase.LoadAssetAtPath(path);
if (shader != null)
shaderName = shader.name;
}
return shaderName;
}
}