[플러그인] 잘못된 Material 파일 검사 도구

앞서'특수효과 발사 입자 수 찾기 도구'한 편을 공유했는데 아직 기억나는지 모르겠다.오늘 나는 다시 이 방식을 따라 사용자 정의의 실용적인 작은 도구를 개발하여 우리의 향후 개발에 더 많은 도움을 제공할 것이다.
게임 프로젝트의 개발에 따라 수요가 끊임없이 변경되고 자원이 끊임없이 개편되면서 프로젝트에 중복되거나 유행이 지난 자원 파일이 대량으로 남아 있기 때문에 우리는 특정한 자원 파일을 찾을 때 여전히 대량의 무용 파일에서 선별하여 작업 효율을 늦춘다.일부 강박증 사람들은 대량의 무용문서가 프로젝트에 존재하는 것을 참지 못하고 일일이 정리하려고 한다.그러나 우리가 수동으로 어떤 쓸모없는 파일을 정리할 때, 때로는 그것이 정말 '쓸모없는 것' 인지 확인할 수 없다. 어쩌면 그것은 여전히 어떤 장면이나 물체에 연관되어 있을지도 모른다.그래서 나는 오늘 Material 파일을 정리하는 것을 예로 삼아 '잘못된 Material 파일 검사 도구' 를 만들었다.
우선, 우리는 먼저 생각을 정리한 다음에 코드를 올리는 것이 좋겠다.
  • 프로젝트 보기에서 선택한 물체를 가져오고 표시합니다(어떤 물체든지 가능하지만 당분간 Material만 처리하면 미래에 다른 물체를 확대 처리할 수 있습니다)
  • 검측이 필요한 물체 경로를 옮겨다니며 현재는 세 가지 검측점으로 나뉜다. 장면, 특수효과, 캐릭터
  • 하나의 Material이 여러 물체와 연결되어 있기 때문에 Dictionary의 형식으로 데이터를 저장하고 분류 표시
  • 감지되면 머티리얼즈와 연관된 물체에 대한 정보를 표시하고, 감지되지 않으면 삭제를 위해 빨간색을 표시하고'삭제'단추를 동반한다.

  • 구체적인 코드는 다음과 같습니다.
    using UnityEngine;
    using System.Collections;
    using UnityEditor;
    using System.Collections.Generic;
    using System.IO;
    
    public class MaterialReferenceChecker : EditorWindow
    {
        Dictionary<string, List<MatDetail>> dictMat = new Dictionary<string, List<MatDetail>>();
        int texWidth = 40;
        int texHeight = 40;
        Vector2 vec2 = new Vector2(0, 0);
        bool isCheck = false;
        bool isCheckScene = true;
        bool isCheckEffect = true;
        bool isCheckCharacter = true;
        GameObject effectObj = null;
        GameObject characterObj = null;
        Object[] objs;
    
        [MenuItem("Tools/Check Material References")]
        public static void Init()
        {
            MaterialReferenceChecker window = GetWindow<MaterialReferenceChecker>();
            window.Show();
        }
    
        void OnGUI()
        {
            if (!isCheck)
            {
                if (objs != null && objs.Length > 100)  //        ,     
                {
                    GUILayout.Label("          (  100 )!       ,   “  ”");
                    if (GUILayout.Button("  "))
                    {
                        objs = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
                    }
                    return;
                }
                objs = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
                GUILayout.BeginHorizontal();
                if (objs == null || objs.Length <= 0)
                {
                    GUILayout.Label("         ,  Project  ,  Ctrl    ");
                    return;
                }
                else
                {
                    GUILayout.Label("        : (" + objs.Length + ") ");
                }
                GUILayout.EndHorizontal();
                vec2 = GUILayout.BeginScrollView(vec2);
                for (int i = 0; i < objs.Length; i++)
                {
                    ListSelections(objs[i]);
                }
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("      "))
                {
                    OnCheckReferences();
                    isCheck = true;
                }
                isCheckScene = GUILayout.Toggle(isCheckScene, "    ", GUILayout.Width(70));
                isCheckEffect = GUILayout.Toggle(isCheckEffect, "    ", GUILayout.Width(70));
                isCheckCharacter = GUILayout.Toggle(isCheckCharacter, "    ", GUILayout.Width(70));
                GUILayout.EndHorizontal();
                ListMaterials();
                GUILayout.EndScrollView();
            }
            else
            {
                //    ,          
                vec2 = GUILayout.BeginScrollView(vec2);
                for (int i = 0; i < objs.Length; i++)
                {
                    ListSelections(objs[i]);
                }
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("  "))
                {
                    isCheck = false;
                    dictMat.Clear();
                }
                GUILayout.EndHorizontal();
                ListMaterials();
                GUILayout.EndScrollView();
            }
        }
    
        //      
        void ListSelections(Object selection)
        {
            GUILayout.BeginHorizontal();
            if (selection is Material || selection is Texture)
            {
                Texture tex = null;
                if (selection is Material)
                {
                    Material mat = selection as Material;
                    if(mat.HasProperty("_MainTex")) tex = mat.mainTexture;
                }
                else if (selection is Texture)
                {
                    tex = selection as Texture;
                }
                if (tex != null)
                {
                    //          
                    if (GUILayout.Button(tex, GUILayout.Width(texWidth), GUILayout.Height(texHeight)))
                    {
                        ZoomInTexture window = GetWindow<ZoomInTexture>();
                        window.texture = tex;
                        window.minSize = new Vector2(tex.width, tex.height);
                    }
                }
                else
                {
                    GUILayout.Box("N/A", GUILayout.Width(texWidth), GUILayout.Height(texHeight));
                }
            }
            else
            {
                GUILayout.Box("N/A", GUILayout.Width(texWidth), GUILayout.Height(texHeight));
            }
            GUILayout.Label("  :"+selection.name + "
    :" + selection.GetType().ToString().Replace("UnityEngine.", "") + "
    :" + AssetDatabase.GetAssetPath(selection)); GUILayout.EndHorizontal(); GUILayout.Space(10); } // void ListMaterials() { if (dictMat == null || dictMat.Count <= 0) { GUILayout.Label(" , “ ” "); return; } foreach (string item in dictMat.Keys) { List<MatDetail> detailList = dictMat[item]; if (detailList != null && detailList.Count > 0) { GUILayout.Space(20); GUILayout.Label("==================《" + item + "》【Material】=================="); foreach (MatDetail detail in detailList) { GUILayout.BeginHorizontal(); // if (detail.mat != null && detail.mat.HasProperty("_MainTex") && detail.mat.mainTexture != null) { if (GUILayout.Button(detail.mat.mainTexture, GUILayout.Width(texWidth), GUILayout.Height(texHeight))) { Selection.activeObject = detail.mat; } } else { if (GUILayout.Button("N/A", GUILayout.Width(texWidth), GUILayout.Height(texHeight))) { Selection.activeObject = detail.mat; } } // string print = ""; if(detail.type == "Effect" || detail.type == "Character") print = string.Format(" :{0}
    :{1}
    :{2}", detail.assetPath, detail.type, detail.hierarcyPath); else print = string.Format(" :{0}
    :{1}
    :{2}", detail.assetPath, detail.type, detail.hierarcyPath); if (detail.type == "NULL") { GUIStyle style = new GUIStyle(); style.normal.textColor = Color.red; GUILayout.Label(print, style); if (GUILayout.Button(" ", GUILayout.Width(40))) { if (AssetDatabase.DeleteAsset(detail.assetPath)) { ShowNotification(new GUIContent(" ")); } } } else { GUILayout.Label(print); } GUILayout.EndHorizontal(); } } } } // void OnCheckReferences() { Object[] objs = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets); if (objs == null || objs.Length <= 0) return; dictMat.Clear(); for (int i = 0; i < objs.Length; i++) { List<MatDetail> listDetail = new List<MatDetail>(); if (objs[i] is Material) { // if (isCheckScene) { if (EditorBuildSettings.scenes.Length <= 0) { Debug.LogError(" , Builder Setting "); return; } foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) { if (scene.enabled) { EditorApplication.OpenScene(scene.path); if (objs[i] is Material) { MatDetail detail = SetMaterial(objs[i], scene.path); if (detail != null) listDetail.Add(detail); } } } } // Resources if (isCheckEffect) { Object[] effects = Resources.LoadAll("Effects"); //Resources , for (int j = 0; j < effects.Length; j++) { if (objs[i] is Material) { MatDetail detail = SetEffectMaterial(objs[i], effects[j]); DestroyImmediate(effectObj); if (detail != null) listDetail.Add(detail); } } } // if (isCheckCharacter) { Object[] characters = GetAssetsOfType(Application.dataPath + "/Characters/", typeof(GameObject), ".prefab"); // , for (int j = 0; j < characters.Length; j++) { if (objs[i] is Material) { MatDetail detail = SetCharactersMaterial(objs[i], characters[j]); DestroyImmediate(characterObj); if (detail != null) listDetail.Add(detail); } } } } // if (listDetail.Count <= 0) { MatDetail detail = new MatDetail(); detail.mat = objs[i] as Material; detail.assetPath = AssetDatabase.GetAssetPath(objs[i]); listDetail.Add(detail); } dictMat.Add(objs[i].name, listDetail); } } // prefab public static Object[] GetAssetsOfType(string directPath, System.Type type, string fileExtension) { List<Object> tempObjects = new List<Object>(); DirectoryInfo directory = new DirectoryInfo(directPath); FileInfo[] goFileInfo = directory.GetFiles("*" + fileExtension, SearchOption.AllDirectories); int goFileInfoLength = goFileInfo.Length; FileInfo tempGoFileInfo; string tempFilePath; Object tempGO; for (int i = 0; i < goFileInfoLength; i++) { tempGoFileInfo = goFileInfo[i]; if (tempGoFileInfo == null) continue; tempFilePath = tempGoFileInfo.FullName; tempFilePath = tempFilePath.Replace(@"\", "/").Replace(Application.dataPath, "Assets"); tempGO = AssetDatabase.LoadAssetAtPath(tempFilePath, typeof(Object)) as Object; if (tempGO == null) { Debug.LogWarning("Skipping Null"); continue; } else if (tempGO.GetType() != type) { Debug.LogWarning("Skipping " + tempGO.GetType().ToString()); continue; } tempObjects.Add(tempGO); } return tempObjects.ToArray(); } // MatDetail SetMaterial(Object obj, string scenePath) { Renderer[] renderers = (Renderer[])FindObjectsOfType(typeof(Renderer)); // , disactive , return GetMatDetail(renderers, obj, scenePath); } // MatDetail SetEffectMaterial(Object select, Object effect) { effectObj = PrefabUtility.InstantiatePrefab(effect) as GameObject; if (effectObj == null) return null; Renderer[] renderers = effectObj.GetComponentsInChildren<Renderer>(true); return GetMatDetail(renderers, select, "Effect"); } // MatDetail SetCharactersMaterial(Object select, Object character) { characterObj = PrefabUtility.InstantiatePrefab(character) as GameObject; if (characterObj == null) return null; SkinnedMeshRenderer[] renderers = characterObj.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer renderer in renderers) { Material[] mats = renderer.sharedMaterials; foreach (Material mat in mats) { string assetPath = AssetDatabase.GetAssetPath(select); if (assetPath == AssetDatabase.GetAssetPath(mat)) { MatDetail detail = new MatDetail(); detail.assetPath = assetPath; detail.mat = mat; detail.type = "Character"; detail.hierarcyPath = GetHierarcyPath(renderer.gameObject); return detail; } } } return null; } // MatDetail MatDetail GetMatDetail(Renderer[] renderers, Object select, string scenePath) { foreach (Renderer renderer in renderers) { // Material[] mats = renderer.sharedMaterials; foreach (Material mat in mats) { string assetPath = AssetDatabase.GetAssetPath(select); if (assetPath == AssetDatabase.GetAssetPath(mat)) { MatDetail detail = new MatDetail(); detail.assetPath = assetPath; detail.mat = mat; detail.type = scenePath; detail.hierarcyPath = GetHierarcyPath(renderer.gameObject); return detail; } } } return null; } // string GetHierarcyPath(GameObject go) { string path = "/" + go.name; while (go.transform.parent != null) { go = go.transform.parent.gameObject; path = "/" + go.name + path; } return path; } // class MatDetail { public Material mat; public string assetPath; public string type; public string hierarcyPath; public MatDetail() { mat = null; assetPath = ""; type = "NULL"; hierarcyPath = "NULL"; } } } // public class ZoomInTexture : EditorWindow { public Texture texture; void OnGUI() { GUILayout.Box(texture, GUILayout.Width(texture.width), GUILayout.Height(texture.height)); } }
    이 도구는 아직 완벽하지 않고 확대하고 최적화해야 할 부분이 많지만 현재의 수요를 충족시킬 수 있다.물론 가장 중요한 것은 하나를 꼽으면 열을 꼽을 수 있고 벽돌을 던져 옥을 끌어올릴 수 있다. 이 사고방식을 통해 도구 플러그인을 더욱 배우고 보완해야 기원과 공유가 가장 큰 발전을 이룰 수 있다.마지막으로 도구 캡처를 드립니다.
    Ricky Yang 개인 창작, 판권 소유, 전재 주석, 감사합니다.http://blog.csdn.net/yangyy753

    좋은 웹페이지 즐겨찾기