【Unity编辑器工具】自动清理项目里不用的shader

一个项目时间久了就会有很多冗余的资源,比如这几天就需要清理一下工程里不用的shader,这就需要写个工具了。

如果只是搜索引用了shader的材质,不够全面,很容易造成资源引用的丢失而出现bug。

经过分析后,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基本不使用,就不做考虑

scene / prefab / material / asset都是序列文本文件,直接读取文本,在文本里搜索shader的guid即可。但cs脚本里对shader的引用与这些不同,需要用shader name在cs脚本里进行搜索,而不是guid。

工具代码如下:

using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;

public class Tools : Editor
{
    [MenuItem("Tools/Clean Useless Shader", priority = 10)]
    public static void CleanUselessShader()
    {
        //先把当前场景和资源的修改保存,以免遗漏或误删
        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();
    }

    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;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值