ShaderCheck

检查统计项目中Shader的使用情况,以及变体数量。

using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

public class ShaderCheck
{
    private static List m_normal_shaders = new List();
    private static List m_build_in_shaders = new List();
    private static List m_standard_shaders = new List();

    private static void CollectShaderInfo()
    {
        m_normal_shaders.Clear();
        m_build_in_shaders.Clear();
        m_standard_shaders.Clear();

        List all_mats = GetAllMaterialInfo();
        List all_sharders = GetAllShaderInfo();


        for (int i = 0; i < all_mats.Count; i++)
        {
            var mat_info = all_mats[i];

            var shader_name = mat_info.Material.shader.name;
            var shader_info = SelectShaderInfo(shader_name, all_sharders);

            if (shader_info == null)
            {
                shader_info = new ShaderCheckInfo
                {
                    Name = shader_name,
                    VariantCount = GetBuildInShaderVariantCount(shader_name)
                };

                if (shader_name == "Standard")
                    FillData(shader_name, m_standard_shaders, shader_info, mat_info);
                else
                    FillData(shader_name, m_build_in_shaders, shader_info, mat_info);
            }
            else
            {
                FillData(shader_name, m_normal_shaders, shader_info, mat_info);
            }

            EditorUtility.DisplayProgressBar("Checking Shader", "checking", (float)(i) / (float)all_mats.Count);
        }

        m_standard_shaders.Sort(new ShaderCheckInfoCompare());
        m_build_in_shaders.Sort(new ShaderCheckInfoCompare());
        m_normal_shaders.Sort(new ShaderCheckInfoCompare());

        EditorUtility.ClearProgressBar();
    }


    [MenuItem(ToolDes.Shader_Import)]
    public static void Import()
    {
        if (EditorUtility.DisplayDialog("Improt Shader", "确定要导入GraphicSetting中么?", "是的"))
        {
            List using_shader = GetUsingShader();
            SerializedObject graphicsSettings = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/GraphicsSettings.asset")[0]);
            SerializedProperty it = graphicsSettings.GetIterator();
            SerializedProperty dataPoint;
            while (it.NextVisible(true))
            {
                if (it.name == "m_AlwaysIncludedShaders")
                {
                    it.ClearArray();
                    for (int i = 0; i < using_shader.Count; i++)
                    {
                        it.InsertArrayElementAtIndex(i);
                        dataPoint = it.GetArrayElementAtIndex(i);
                        dataPoint.objectReferenceValue = Shader.Find(using_shader[i]);
                    }
                    graphicsSettings.ApplyModifiedProperties();
                }
            }
        }
    }

    private static List GetUsingShader()
    {
        CollectShaderInfo();
        List shaders_name_list = new List();
        foreach (var shader in m_build_in_shaders)
        {
            shaders_name_list.Add(shader.Name);
        }
        return shaders_name_list;

        //List shaders_name_list = new List();
        //var mats = AssetDatabase.FindAssets("t:material");
        //int index = 0;
        //foreach (var mat in mats)
        //{
        //    index++;
        //    var path = AssetDatabase.GUIDToAssetPath(mat);
        //    var real_mat = AssetDatabase.LoadAssetAtPath(path) as Material;

        //    if (real_mat != null)
        //    {
        //        if (real_mat.shader.name == "Standard")
        //        {
        //            continue;
        //        }

        //        if (!shaders_name_list.Contains(real_mat.shader.name))
        //            shaders_name_list.Add(real_mat.shader.name);
        //    }
        //    EditorUtility.DisplayProgressBar("Checking Shader", "import_shader:" + path, (float)(index) / (float)mats.Length);
        //}
        //EditorUtility.ClearProgressBar();
        //return shaders_name_list;
    }


    [MenuItem(ToolDes.Shader_Check)]
    public static void Check()
    {
        CollectShaderInfo();

        var title = "材质总数: " + GetAllMaterialInfo().Count 
            + "   使用Shader总数: " + (m_normal_shaders.Count + m_standard_shaders.Count + m_build_in_shaders.Count)
            + "   BuildIn_Shader总数: " + m_build_in_shaders.Count
            + "   Project_Shader总数: " + m_normal_shaders.Count;

        //导出
        ExprotDescription(GetDescription(m_normal_shaders, m_standard_shaders, m_build_in_shaders), title);
    }

    private static void FillData(string shader_name, List shaders, ShaderCheckInfo shader_info, MaterialCheckInfo mat_info)
    {
        var s_shader_info = SelectShaderInfo(shader_name, shaders);
        if (s_shader_info == null)
        {
            shader_info.m_mat_info.Add(mat_info);
            shaders.Add(shader_info);
        }
        else
        {
            s_shader_info.m_mat_info.Add(mat_info);
        }
    }

    private static List GetAllMaterialInfo()
    {
        List materials = new List();
        var mats = AssetDatabase.FindAssets("t:material");
        int index = 0;
        foreach (var mat in mats)
        {
            index++;
            var path = AssetDatabase.GUIDToAssetPath(mat);
            var real_mat = AssetDatabase.LoadAssetAtPath(path) as Material;


            MaterialCheckInfo info = new MaterialCheckInfo();
            info.Name = real_mat.name;
            info.Path = path;
            info.Material = real_mat;

            materials.Add(info);

            EditorUtility.DisplayProgressBar("Checking Shader", "get_materials:" + path, (float)(index) / (float)mats.Length);
        }
        EditorUtility.ClearProgressBar();

        return materials;
    }

    private static List GetAllShaderInfo()
    {
        List shaders = new List();

        var method = GetVariantCountMethodInfo();

        var shader_list = AssetDatabase.FindAssets("t:Shader");
        int index = 0;
        foreach (var shader in shader_list)
        {
            index++;

            var path = AssetDatabase.GUIDToAssetPath(shader);
            Shader target_shader = AssetDatabase.LoadAssetAtPath(path) as Shader;

            var count = method.Invoke(null, new System.Object[] { target_shader, true });

            ShaderCheckInfo info = new ShaderCheckInfo();
            info.Name = target_shader.name;
            info.Path = path;
            info.VariantCount = (ulong)count;

            shaders.Add(info);

            EditorUtility.DisplayProgressBar("Checking Shader", "get_shaders:" + path, (float)(index) / (float)shader_list.Length);
        }

        EditorUtility.ClearProgressBar();

        return shaders;
    }

    private static ulong GetBuildInShaderVariantCount(string shader_name)
    {
        var method = GetVariantCountMethodInfo();
        Shader target_shader = Shader.Find(shader_name);
        var count = method.Invoke(null, new System.Object[] { target_shader, true });
        return (ulong)count;
    }

    private static MethodInfo GetVariantCountMethodInfo()
    {
        Assembly asm = Assembly.LoadFile(@"D:\work_tool\unity_2018.3.6f1\Unity\Editor\Data\Managed\UnityEditor.dll");
        System.Type shader_util = asm.GetType("UnityEditor.ShaderUtil");
        MethodInfo method = shader_util.GetMethod("GetVariantCount", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

        return method;
    }

    private static ShaderCheckInfo SelectShaderInfo(string shader_name, List shaders)
    {
        foreach (var item in shaders)
        {
            if (item.Name == shader_name)
            {
                return item;
            }
        }

        return null;
    }

    private static List GetDescription(List normal_shaders, List standard_shaders, List build_in_shaders)
    {
        List des = new List();
        des.Add("Standard Shader:" + "\r\n");
        foreach (var item in standard_shaders)
        {
            des.Add(item.ToString());
        }
        des.Add("Build_In Shader:" + "\r\n");
        foreach (var item in build_in_shaders)
        {
            des.Add(item.ToString());
        }
        des.Add("Normal Shader:" + "\r\n");
        foreach (var item in normal_shaders)
        {
            des.Add(item.ToString());
        }

        return des;
    }

    private static void ExprotDescription(List des, string title = "")
    {
        var save_path = Application.dataPath + "/shader_report.txt";
        FileUtil.Export(save_path, des, title);
    }

}


public class MaterialCheckInfo
{
    private string m_name = "";      //材质名称
    public string Name { get { return m_name; } set { m_name = value; } }

    private string m_path = "";      //材质路径
    public string Path { get { return m_path; } set { m_path = value; } }

    private Material m_material;     //材质
    public Material Material { get { return m_material; } set { m_material = value; } }

}


public class ShaderCheckInfo
{

    private string m_name = "";      //shader名称
    public string Name { get { return m_name; } set { m_name = value; } }

    private string m_path = "";      //shader路径
    public string Path { get { return m_path; } set { m_path = value; } }

    private ulong m_variant_count = 0; //shader变体数量
    public ulong VariantCount { get { return m_variant_count; } set { m_variant_count = value; } }

    public List m_mat_info = new List();  //使用当前Shader的材质列表

    public string GetMaterialDes(List infos)
    {
        var des = "";
        for (int i = 0; i < infos.Count; i++)
        {
            var info = infos[i];
            des = des + "        " + "Material Name: " + info.Name + "   Path: " + info.Path + "\r\n";
        }
        return des;
    }

    public override string ToString()
    {
        return "Shader: " + Name + "  Path: " + Path + "  VariantCount: " + VariantCount + "\r\n" + GetMaterialDes(m_mat_info);
    }
}

public class ShaderCheckInfoCompare : IComparer
{
    public int Compare(ShaderCheckInfo x, ShaderCheckInfo y)
    {
        if (x.VariantCount > y.VariantCount)
            return -1;

        return 1;
    }
}

你可能感兴趣的:(ShaderCheck)