清理未使用的shader

 


/******************************************************************************
 * 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 <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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值