/******************************************************************************* DESCRIPTION: 清理未使用的shader* CREATED: 2020.09.24 * shader在绝大多数情况下,会在以下几种情况里附加上资源:1. 最常见的,使用了shader的material2. 比较常见的,cs脚本里直接用Shader.Find(shaderName)进行动态加载shader3. 这个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文件的文本里搜寻该guidstring[] 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 <color=#78DDFF>{0}</color>", shaderName);}}AssetDatabase.SaveAssets();AssetDatabase.Refresh();}/// <summary>/// 检查一个shader是否无用/// </summary>/// <param name="checkType"></param>/// <param name="shaderGUID"></param>/// <param name="shaderName"></param>/// <returns></returns>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<string> paths = new List<string>(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<Shader>(path);if (shader != null)shaderName = shader.name;}return shaderName;}
}