{"id":6290,"date":"2026-01-06T16:31:52","date_gmt":"2026-01-06T08:31:52","guid":{"rendered":"https:\/\/blog.coolcoding.cn\/?p=6290"},"modified":"2026-01-06T16:32:24","modified_gmt":"2026-01-06T08:32:24","slug":"prefab%e8%b5%84%e6%ba%90%e5%bc%95%e7%94%a8%e6%9f%a5%e6%89%be%e5%b7%a5%e5%85%b7","status":"publish","type":"post","link":"https:\/\/blog.coolcoding.cn\/?p=6290","title":{"rendered":"\u7cbe\u786e\u7684Prefab\u8d44\u6e90\u5f15\u7528\u67e5\u627e\u5de5\u5177"},"content":{"rendered":"\n<p>\u4e00\u822c\u7684Prefab\u5f15\u7528\u67e5\u627e\u5de5\u5177\uff0c\u53ea\u80fd\u67e5\u627ePrefb\u5f15\u7528\u4e86\uff0c\u4f46\u662f\u54ea\u4e2a\u8282\u70b9\u5f15\u7528\u4e86\u4e0d\u77e5\u9053\uff0c\u4ee5\u4e0b\u5de5\u5177\u53ef\u4ee5\u7cbe\u786e\u5b9a\u4f4d\u662f\u54ea\u4e2a\u8282\u70b9\u4f7f\u7528\u7684<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using UnityEditor;\r\nusing UnityEngine;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing UnityEditor.SceneManagement;\r\nusing UnityEditor.Animations;\r\npublic class PrefabRefFindTool: EditorWindow\r\n{\r\n    &#91;MenuItem(\"Tools\/\u6253\u5f00Prefab\u8d44\u6e90\u67e5\u627e\u5de5\u5177\", false, 3502)]\r\n    private static void ShowWindow()\r\n    {\r\n        var window = GetWindow&lt;PrefabRefFindTool>(\"Prefab\u8d44\u6e90\u67e5\u627e\u5de5\u5177\");\r\n        window.Show();\r\n    }\r\n\r\n    public static bool UseDebugPath = false;\r\n\r\n    public class FilterObject\r\n    {\r\n        private List&lt;string> mExcludeFilter = new List&lt;string>();\r\n        private List&lt;string> mIncludeFilter = new List&lt;string>();\r\n        private List&lt;string> mFileTypeFilter = new List&lt;string>();\r\n\r\n        public FilterObject(string excludeStr, string includeStr, string&#91;] fileTypeFilter)\r\n        {\r\n            \/\/ \u8fc7\u6ee4\u6389Unity\u5185\u7f6e\u8d44\u6e90\r\n            mExcludeFilter.Add(\"unity_builtin_extra\");\r\n            mExcludeFilter.Add(\"library\/\");\r\n            mExcludeFilter.Add(\"packages\/\");\r\n\r\n            var exclude = excludeStr.ToLower().Split(';');\r\n            foreach (var item in exclude)\r\n            {\r\n                var txt = item.Trim();\r\n                if (txt.Length > 0)\r\n                {\r\n                    mExcludeFilter.Add(txt);\r\n                }\r\n            }\r\n\r\n            var include = includeStr.ToLower().Split(';');\r\n            foreach (var item in include)\r\n            {\r\n                var txt = item.Trim();\r\n                if (txt.Length > 0)\r\n                {\r\n                    mIncludeFilter.Add(txt);\r\n                }\r\n            }\r\n\r\n            mFileTypeFilter.AddRange(fileTypeFilter);\r\n        }\r\n    \r\n        public bool IsShow(string input0)\r\n        {\r\n            var input = input0.ToLower();\r\n            if (mExcludeFilter.Count > 0)\r\n            {\r\n                foreach (var str in mExcludeFilter)\r\n                {\r\n                    if (input.Contains(str))\r\n                    {\r\n                        return false;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (mFileTypeFilter.Count > 0)\r\n            {\r\n                bool container = false;\r\n                foreach (var str in mFileTypeFilter)\r\n                {\r\n                    if (input.Contains(str))\r\n                    {\r\n                        container = true;\r\n                        break;\r\n                    }\r\n                }\r\n                if (!container)\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            if (mIncludeFilter.Count > 0)\r\n            {\r\n                bool container = false;\r\n                foreach (var str in mIncludeFilter)\r\n                {\r\n                    if (input.Contains(str))\r\n                    {\r\n                        container = true;\r\n                        break;\r\n                    }\r\n                }\r\n                if (!container)\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            return true;\r\n        }\r\n    }\r\n\r\n    public class PrefabRefInfos\r\n    {\r\n\r\n        \/\/ prefabPath : List&lt;nodePath>\r\n        public Dictionary&lt;string, List&lt;(string path, string etype)>> mPrefabRefInfos = new ();\r\n        public bool mFoldout = false;\r\n        public bool mSelected = false;\r\n        private string mETypes = \"\";\r\n        public string ETypes => mETypes;\r\n\r\n        public void AddRefInfo(string prefabPath, string nodePath, string eType)\r\n        {\r\n            if (!mPrefabRefInfos.TryGetValue(prefabPath, out var nodePaths))\r\n            {\r\n                nodePaths = new List&lt;(string path, string etype)>();\r\n                mPrefabRefInfos.Add(prefabPath, nodePaths);\r\n            }\r\n\r\n            bool contain = false;\r\n            foreach(var (path, etype) in nodePaths)\r\n            {\r\n                if (path == nodePath)\r\n                {\r\n                    contain = true;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (!mETypes.Contains(eType))\r\n            {\r\n                mETypes += $\"{eType};\";\r\n            }\r\n\r\n            if (!contain)\r\n            {\r\n                nodePaths.Add((nodePath, eType));\r\n            }\r\n        }\r\n\r\n        public (string, string) Draw( (string p3, string p4) prev)\r\n        {\r\n            var (p1, p2) = (string.Empty, string.Empty);\r\n\r\n            EditorGUILayout.BeginVertical(\"box\");\r\n\r\n            foreach (var kv in mPrefabRefInfos)\r\n            {\r\n                var prefabPath = kv.Key;\r\n                var nodePaths = kv.Value;\r\n\r\n                EditorGUILayout.BeginHorizontal();\r\n                \r\n                EditorGUILayout.LabelField(prefabPath);\r\n                \r\n                if (GUILayout.Button(\"\u5168\u9009\u8282\u70b9\", GUILayout.Width(70)))\r\n                {\r\n                    List&lt;string> list = new List&lt;string>();\r\n                    foreach(var (nodePath, eType) in nodePaths)\r\n                    {\r\n                        list.Add(nodePath);\r\n                    }\r\n                    SelectAllNode(prefabPath, list);\r\n                }\r\n\r\n                DrawLocationButton(prefabPath);\r\n\r\n                EditorGUILayout.EndHorizontal();\r\n\r\n                foreach (var (nodePath, eType) in nodePaths)\r\n                {\r\n                    EditorGUILayout.BeginHorizontal();\r\n\r\n                    var title = \">\";\r\n                    if (prev.p3 == prefabPath &amp;&amp; prev.p4 == nodePath)\r\n                    {\r\n                        title = \"* >\";\r\n                    }\r\n\r\n                    if (GUILayout.Button(title, GUILayout.Width(30)))\r\n                    {\r\n                        var ret = SelectNodeByPath(prefabPath, nodePath);\r\n                        if (ret != 0)\r\n                        {\r\n                            Log.EditorInfo($\"\u9009\u4e2d{nodePath}\u8282\u70b9\u5931\u8d25\uff0c\u9519\u8bef\u7801\uff1a{ret}\");\r\n                        }\r\n                        else\r\n                        {\r\n                            p1 = prefabPath;\r\n                            p2 = nodePath;\r\n                        }\r\n                    }\r\n\r\n                    EditorGUILayout.LabelField(nodePath);\r\n                    EditorGUILayout.EndHorizontal();\r\n                }\r\n            \r\n            }\r\n\r\n            EditorGUILayout.EndVertical();\r\n\r\n            return (p1, p2);\r\n        }\r\n    }\r\n\r\n    private static void SelectAllNode(string prefabPath, List&lt;string> nodePaths)\r\n    {\r\n        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();\r\n        if (prefabStage != null)\r\n        {\r\n            if (prefabStage.assetPath != prefabPath)\r\n            {\r\n                PrefabStageUtility.OpenPrefab(prefabPath);\r\n                prefabStage = PrefabStageUtility.GetCurrentPrefabStage();\r\n            }\r\n        }\r\n        else\r\n        {\r\n            PrefabStageUtility.OpenPrefab(prefabPath);\r\n            prefabStage = PrefabStageUtility.GetCurrentPrefabStage();\r\n        }\r\n\r\n        var rootNode = prefabStage.prefabContentsRoot;\r\n        if (rootNode == null)\r\n        {\r\n            return;\r\n        }\r\n\r\n        List&lt;GameObject> collect = new List&lt;GameObject>();\r\n        for(int i=0; i&lt;nodePaths.Count; ++i)\r\n        {\r\n            var node = FindNodeByPath(rootNode, nodePaths&#91;i]);\r\n            if (node != null)\r\n            {\r\n                collect.Add(node.gameObject);\r\n            }\r\n        }\r\n\r\n        if (collect.Count > 0)\r\n        {\r\n            Selection.objects = collect.ToArray();\r\n        }\r\n    }\r\n\r\n    private static GameObject FindNodeByPath(GameObject parentNode, string nodePath)\r\n    {\r\n        var nodePaths = nodePath.Split('\/');\r\n        if (nodePaths.Length == 0)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        if (nodePaths&#91;0] != parentNode.name)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        var node = parentNode.transform;\r\n        for(int i=1; i&lt;nodePaths.Length; i++)\r\n        {\r\n            node = node.transform.Find(nodePaths&#91;i]);\r\n            if (node == null)\r\n            {\r\n                break;\r\n            }\r\n        }\r\n\r\n        if (node != null)\r\n        {\r\n            return node.gameObject;\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    private static int SelectNodeByPath(string prefabPath, string nodePath)\r\n    {\r\n        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();\r\n        if (prefabStage != null)\r\n        {\r\n            if (prefabStage.assetPath != prefabPath)\r\n            {\r\n                PrefabStageUtility.OpenPrefab(prefabPath);\r\n                prefabStage = PrefabStageUtility.GetCurrentPrefabStage();\r\n            }\r\n        }\r\n        else\r\n        {\r\n            PrefabStageUtility.OpenPrefab(prefabPath);\r\n            prefabStage = PrefabStageUtility.GetCurrentPrefabStage();\r\n        }\r\n\r\n        var nodePaths = nodePath.Split('\/');\r\n        if (nodePaths.Length == 0)\r\n        {\r\n            return -3;\r\n        }\r\n\r\n        var rootNode = prefabStage.prefabContentsRoot;\r\n        if (rootNode == null)\r\n        {\r\n            return -4;\r\n        }\r\n\r\n        if (nodePaths&#91;0] != rootNode.name)\r\n        {\r\n            return -5;\r\n        }\r\n\r\n        var node = rootNode.transform;\r\n        for(int i=1; i&lt;nodePaths.Length; i++)\r\n        {\r\n            node = node.transform.Find(nodePaths&#91;i]);\r\n            if (node == null)\r\n            {\r\n                break;\r\n            }\r\n        }\r\n        if (node == null)\r\n        {\r\n            return -6;\r\n        }\r\n\r\n        Selection.activeTransform = node;\r\n        return 0;\r\n    }\r\n\r\n    private static void DrawLocationButton(string prefabPath)\r\n    {\r\n        if (GUILayout.Button(\"\u5b9a\u4f4d\", GUILayout.Width(40)))\r\n        {\r\n            var selectObj = AssetDatabase.LoadAssetAtPath&lt;Object>(prefabPath);\r\n            if (selectObj != null)\r\n            {\r\n                Selection.activeObject = selectObj;\r\n            }\r\n        }\r\n    }\r\n\r\n    private Vector2 mMainScrollPos = Vector2.zero;\r\n    private DefaultAsset mTargetDir;\r\n    private Dictionary&lt;string, PrefabRefInfos> mTexturePathDict = new ();\r\n    private string mExcludeStr = \"\";\r\n    private string mIncludeStr = \"\";\r\n    private string mFilterStr = \"\";\r\n    private readonly string&#91;] kShowFilters = new string&#91;]\r\n    {\r\n        \"\u5168\u90e8\",   \/\/ 0\r\n        \"\u4ec5\u56fe\u7247\", \/\/ 1\r\n        \"\u4ec5FBX\",  \/\/ 2\r\n        \"\u4ec5\u6750\u8d28\", \/\/ 3\r\n    };\r\n\r\n    private readonly string&#91;]&#91;] kShowFilterArray = new string&#91;]&#91;]\r\n    {\r\n        new string&#91;] {},\r\n        new string&#91;] {\".png\", \".jpg\", \".tga\"},\r\n        new string&#91;] {\".fbx\"},\r\n        new string&#91;] {\".mat\"},\r\n    };\r\n\r\n    private int mShowType = 0;\r\n\r\n    private void SetAllSelectState(bool selected)\r\n    {\r\n        foreach (var kv in mTexturePathDict)\r\n        {\r\n            kv.Value.mSelected = !selected;\r\n        }\r\n\r\n        var filter = GetFilterObj();\r\n        List&lt;string> keys = new List&lt;string>(mTexturePathDict.Keys);\r\n        keys.Sort();\r\n        foreach(var key in keys)\r\n        {\r\n            if (filter.IsShow(key))\r\n            {\r\n                mTexturePathDict&#91;key].mSelected = selected;\r\n            }\r\n        }\r\n    }\r\n\r\n    private bool mUseUnityDepSys = false;\r\n\r\n    private void OnGUI()\r\n    {\r\n        EditorGUILayout.BeginHorizontal();\r\n        if (GUILayout.Button(\"\u9884\u89c8\u9009\u4e2d\", GUILayout.Width(80)))\r\n        {\r\n            PreviewImages();\r\n        }\r\n\r\n        if (GUILayout.Button(\"\u5168\u9009\", GUILayout.Width(70)))\r\n        {\r\n            SetAllSelectState(true);\r\n        }\r\n        if (GUILayout.Button(\"\u5168\u4e0d\u9009\", GUILayout.Width(70)))\r\n        {\r\n            SetAllSelectState(false);\r\n        }\r\n\r\n        EditorGUILayout.EndHorizontal();\r\n\r\n        EditorGUILayout.BeginHorizontal();\r\n                \r\n        var newShowType = EditorGUILayout.Popup(mShowType, kShowFilters, GUILayout.Width(80));\r\n        if (newShowType != mShowType)\r\n        {\r\n            mShowType = newShowType;\r\n            \r\n        }\r\n\r\n        EditorGUILayout.LabelField(\"\u6392\u9664\", GUILayout.Width(30));\r\n        mExcludeStr = EditorGUILayout.TextField(mExcludeStr, GUILayout.Width(100));\r\n\r\n        EditorGUILayout.LabelField(\"  \", GUILayout.Width(5));\r\n\r\n        EditorGUILayout.LabelField(\"\u5305\u542b\", GUILayout.Width(30));\r\n        mIncludeStr = EditorGUILayout.TextField(mIncludeStr, GUILayout.Width(100));\r\n\r\n\r\n\r\n        EditorGUILayout.EndHorizontal();\r\n\r\n        EditorGUILayout.BeginHorizontal();\r\n        EditorGUILayout.LabelField(\"\u79fb\u52a8\u7eb9\u7406\u5230\", GUILayout.Width(80));\r\n        mTargetDir = (DefaultAsset)EditorGUILayout.ObjectField(\"\", mTargetDir, typeof(DefaultAsset), false, GUILayout.Width(160));\r\n        if (mTargetDir != null &amp;&amp; GUILayout.Button(\"\u79fb\u52a8\", GUILayout.Width(80)))\r\n        {\r\n            MoveSelectImages();\r\n        }\r\n\r\n        EditorGUILayout.LabelField(\"  \", GUILayout.Width(5));\r\n        mUseUnityDepSys = EditorGUILayout.Toggle(mUseUnityDepSys, GUILayout.Width(20));\r\n        EditorGUILayout.LabelField(\"\u4f7f\u7528Unity\u4f9d\u8d56\", GUILayout.Width(80));\r\n\r\n        UseDebugPath = EditorGUILayout.Toggle(UseDebugPath, GUILayout.Width(20));\r\n        EditorGUILayout.LabelField(\"\u5f15\u7528\u8fc7\u6ee4\", GUILayout.Width(50));\r\n        if (UseDebugPath)\r\n        {\r\n            mFilterStr = EditorGUILayout.TextField(mFilterStr, GUILayout.Width(80));\r\n        }\r\n\r\n        EditorGUILayout.EndHorizontal();\r\n\r\n        \r\n        EditorGUILayout.BeginVertical();\r\n        mMainScrollPos = EditorGUILayout.BeginScrollView(mMainScrollPos);\r\n\r\n        List&lt;string> keys = new List&lt;string>(mTexturePathDict.Keys);\r\n        keys.Sort();\r\n\r\n        var filter = GetFilterObj();\r\n        foreach(var key in keys)\r\n        {\r\n            if (!filter.IsShow(key))\r\n            {\r\n                continue;\r\n            }\r\n \r\n            var currTexInfo = mTexturePathDict&#91;key];\r\n            if (UseDebugPath &amp;&amp; mFilterStr.Length > 0)\r\n            {\r\n                if (!currTexInfo.ETypes.Contains(mFilterStr))\r\n                {\r\n                    continue;\r\n                }\r\n            }\r\n           \r\n            EditorGUILayout.BeginHorizontal();\r\n            currTexInfo.mSelected = EditorGUILayout.Toggle(currTexInfo.mSelected, GUILayout.Width(20));\r\n            currTexInfo.mFoldout = EditorGUILayout.Foldout(currTexInfo.mFoldout, key);\r\n            DrawLocationButton(key);\r\n            EditorGUILayout.EndHorizontal();\r\n\r\n            if (currTexInfo.mFoldout)\r\n            {\r\n                (var p0, var p1) = currTexInfo.Draw(mLastSelectInfo);\r\n                if(p0.Length > 0 &amp;&amp; p1.Length > 0)\r\n                {\r\n                    mLastSelectInfo = (p0, p1);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (UseDebugPath)\r\n                {\r\n                    EditorGUILayout.LabelField(currTexInfo.ETypes);\r\n                }\r\n            }\r\n        }\r\n\r\n        EditorGUILayout.EndScrollView();\r\n        EditorGUILayout.EndVertical();\r\n\r\n        if (keys.Count == 0)\r\n        {\r\n            EditorGUILayout.HelpBox(\"\u6392\u9664\u548c\u5305\u542b\uff0c\u4ee5;(\u5206\u53f7)\u5206\u9694\", MessageType.Info);\r\n        }\r\n    }\r\n\r\n    private (string lastP0, string lastP1) mLastSelectInfo = (string.Empty, string.Empty);\r\n\r\n    private FilterObject GetFilterObj()\r\n    {\r\n        var filterArray = kShowFilterArray&#91;mShowType];\r\n        return new FilterObject(mExcludeStr, mIncludeStr, filterArray);\r\n    }\r\n\r\n    private void MoveSelectImages()\r\n    {\r\n        var targetDirPath = AssetDatabase.GetAssetPath(mTargetDir);\r\n        if (!targetDirPath.StartsWith(\"Assets\/\"))\r\n        {\r\n            Log.EditorError(\"\u76ee\u6807\u76ee\u5f55\u5fc5\u987b\u5728Assets\u76ee\u5f55\u4e0b\");\r\n            return;\r\n        }\r\n    \r\n        StringBuilder sb = new StringBuilder();\r\n        foreach (var kv in mTexturePathDict)\r\n        {\r\n            if (!kv.Value.mSelected)\r\n            {\r\n                continue;\r\n            }\r\n\r\n            var ret = MoveImageAsset(kv.Key, targetDirPath);\r\n            sb.AppendLine(ret);\r\n        }\r\n\r\n        Log.EditorInfo(sb.ToString());\r\n    }\r\n\r\n    private string MoveImageAsset(string srcImagePath, string targetDirPath)\r\n    {\r\n        if (!System.IO.File.Exists(srcImagePath))\r\n        {\r\n            return $\"{srcImagePath}\u6587\u4ef6\u4e0d\u5b58\u5728\";\r\n        }\r\n\r\n        var fileName = System.IO.Path.GetFileName(srcImagePath);\r\n        var destImagePath = System.IO.Path.Combine(targetDirPath, fileName);\r\n        if (System.IO.File.Exists(destImagePath))\r\n        {\r\n            return $\"{destImagePath}\u6587\u4ef6\u5df2\u5b58\u5728\";\r\n        }\r\n\r\n        if (srcImagePath == destImagePath)\r\n        {\r\n            return $\"{srcImagePath}\u548c{destImagePath}\u76f8\u540c\";\r\n        }\r\n\r\n        AssetDatabase.MoveAsset(srcImagePath, destImagePath);\r\n        return $\"\u79fb\u52a8\u6210\u529f: {srcImagePath} -> {destImagePath}\";\r\n    }\r\n\r\n\r\n    private void PreviewImages()\r\n    {\r\n        mTexturePathDict.Clear();\r\n\r\n        StringBuilder sb = new StringBuilder();\r\n\r\n        var (type, dir) = EditorHelper.GetCurrSelectAssetPath();\r\n        if ( type == \"dir\")\r\n        {\r\n            var files = System.IO.Directory.GetFiles(dir, \"*.prefab\", System.IO.SearchOption.AllDirectories);\r\n            foreach (var assetPath in files)\r\n            {\r\n                sb.Append(assetPath.Replace(\"\\\\\", \"\/\"));\r\n                sb.Append(\";\");\r\n            }\r\n        }\r\n        else\r\n        {\r\n            var selectedObjs = Selection.objects;\r\n            if (selectedObjs.Length == 0)\r\n            {\r\n                Log.EditorError($\"\u8bf7\u5728Project\u4e2d, \u9009\u62e9\u8981\u9884\u89c8\u7684Prefab\uff0c\u53ef\u4ee5\u591a\u9009\");\r\n                return;\r\n            }\r\n            foreach (var obj in selectedObjs)\r\n            {\r\n                var assetPath = AssetDatabase.GetAssetPath(obj);\r\n                if (!string.IsNullOrEmpty(assetPath))\r\n                {\r\n                    sb.Append(assetPath);\r\n                    sb.Append(\";\");\r\n                }\r\n            }\r\n        }\r\n\r\n        var str = sb.ToString();\r\n        PreviewImages(str);\r\n    }\r\n\r\n    private void PreviewImages(string prefabAssetPaths)\r\n    {\r\n        CollectAndPreviewImages(mTexturePathDict, prefabAssetPaths, mUseUnityDepSys);\r\n    }\r\n\r\n    private static void CollectMatTextures(Material material, List&lt;string> texturePaths)\r\n    {\r\n        var shader = material.shader;\r\n        if (shader == null)\r\n        {\r\n            return;\r\n        }\r\n\r\n        var propCount = shader.GetPropertyCount();\r\n        for (int i = 0; i &lt; propCount; i++)\r\n        {\r\n            if (shader.GetPropertyType(i) != UnityEngine.Rendering.ShaderPropertyType.Texture)\r\n            {\r\n                continue;\r\n            }\r\n\r\n            var propName = shader.GetPropertyName(i);\r\n            if (string.IsNullOrEmpty(propName))\r\n            {\r\n                continue;\r\n            }\r\n\r\n            var texture = material.GetTexture(propName);\r\n            if (texture == null)\r\n            {\r\n                continue;\r\n            }\r\n        \r\n            var texPath = AssetDatabase.GetAssetPath(texture);\r\n            if (string.IsNullOrEmpty(texPath))\r\n            {\r\n                continue;\r\n            }\r\n\r\n            if (texturePaths.Contains(texPath))\r\n            {\r\n                continue;\r\n            }\r\n\r\n            texturePaths.Add(texPath);\r\n        }\r\n    }\r\n    public delegate void CollectFunc(string prefabAssetPath, Dictionary&lt;string, PrefabRefInfos> pool);\r\n\r\n    \/\/ \u6536\u96c6\u6240\u6709\u7684\u5f15\u7528\r\n    private static void CollectSelectPrefabAssets(string prefabAssetPath, Dictionary&lt;string, PrefabRefInfos> pool)\r\n    {\r\n        var prefab = AssetDatabase.LoadAssetAtPath&lt;GameObject>(prefabAssetPath);\r\n        if (prefab == null)\r\n        {\r\n            return;\r\n        }\r\n\r\n        \/\/ \u8ffd\u52a0\u5f15\u7528\r\n        void AppendAssetRef(GameObject node, string newAssetPath, string reason)\r\n        {\r\n            if (node == null || string.IsNullOrEmpty(newAssetPath))\r\n            {\r\n                return;\r\n            }\r\n\r\n            if (!pool.TryGetValue(newAssetPath, out var info))\r\n            {\r\n                info = new PrefabRefInfos();\r\n                pool.Add(newAssetPath, info);\r\n            }\r\n            var fullPathName = node.GetFullPathName();\r\n            info.AddRefInfo(prefabAssetPath, fullPathName, reason);\r\n        }\r\n\r\n        \/\/ \u6536\u96c6GameObject\u5f15\u7528\u7684\u8d34\u56fe\r\n        void AppendObjRef(GameObject node, UnityEngine.Object refObj, string reason)\r\n        {\r\n            if (refObj == null)\r\n            {\r\n                return;\r\n            }\r\n\r\n            AppendAssetRef(node, AssetDatabase.GetAssetPath(refObj), reason);\r\n\r\n            if (refObj is Material)\r\n            {\r\n                \/\/ \u5982\u679c\u662f\u6750\u8d28\uff0c\u8fd8\u9700\u8981\u6536\u96c6\u6750\u8d28\u4e2d\u5f15\u7528\u7684\u8d34\u56fe\r\n                var materialObj = refObj as Material;\r\n                List&lt;string> texturePaths = new List&lt;string>();\r\n                CollectMatTextures(materialObj, texturePaths);\r\n                foreach (var texturePath in texturePaths)\r\n                {\r\n                    AppendAssetRef(node, texturePath, reason);\r\n                }\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6Image\r\n        var images = prefab.GetComponentsInChildren&lt;UnityEngine.UI.Image>(true);\r\n        foreach (var image in images)\r\n        {\r\n            if (image.mainTexture != null)\r\n            {\r\n                AppendObjRef(image.gameObject, image.mainTexture, \"MainTex-Image\");\r\n            }\r\n\r\n            if (image.material != null)\r\n            {\r\n                AppendObjRef(image.gameObject, image.material, \"Material-Image\");\r\n                AppendObjRef(image.gameObject, image.material.mainTexture, \"MainTex-ImageMaterial\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6RawImage\r\n        var rawImages = prefab.GetComponentsInChildren&lt;UnityEngine.UI.RawImage>(true);\r\n        foreach (var rawImage in rawImages)\r\n        {\r\n            if (rawImage.mainTexture != null)\r\n            {\r\n                AppendObjRef(rawImage.gameObject, rawImage.mainTexture, \"MainTex-RawImage\");\r\n            }\r\n\r\n            if (rawImage.material != null)\r\n            {\r\n                AppendObjRef(rawImage.gameObject, rawImage.material, \"Material-RawImage\");\r\n                AppendObjRef(rawImage.gameObject, rawImage.material.mainTexture, \"Material-MainTex\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6SpriteRenderer\r\n        var spriteRenderers = prefab.GetComponentsInChildren&lt;SpriteRenderer>(true);\r\n        foreach (var spriteRenderer in spriteRenderers)\r\n        {\r\n            if (spriteRenderer.sprite &amp;&amp; spriteRenderer.sprite.texture)\r\n            {\r\n                AppendObjRef(spriteRenderer.gameObject, spriteRenderer.sprite.texture, \"MainTex-SpriteRenderer\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6\u6e32\u67d3\u5668\r\n        var renderers = prefab.GetComponentsInChildren&lt;Renderer>(true);\r\n        foreach (var renderer in renderers)\r\n        {\r\n            if (renderer.sharedMaterial != null)\r\n            {\r\n                AppendObjRef(renderer.gameObject, renderer.sharedMaterial, \"Material-Renderer\");\r\n                AppendObjRef(renderer.gameObject, renderer.sharedMaterial.mainTexture, \"Material-MainTex\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6MeshCollider\u4e2d\u7684FBX\u4e2d\r\n        var meshColliders = prefab.GetComponentsInChildren&lt;MeshCollider>(true);\r\n        foreach (var meshCollider in meshColliders)\r\n        {\r\n            if (meshCollider.sharedMesh != null)\r\n            {\r\n                AppendObjRef(meshCollider.gameObject, meshCollider.sharedMesh, \"Mesh-MeshCollider\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6Animation\u4e2d\u7684Clip\r\n        var animations = prefab.GetComponentsInChildren&lt;Animation>(true);\r\n        foreach (var animation in animations)\r\n        {\r\n            if (animation.clip != null)\r\n            {\r\n                AppendObjRef(animation.gameObject, animation.clip, \"AnimationClip\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6\u7c92\u5b50\u7cfb\u7edf\u4e2d\u7684Mesh\r\n        void AppendSharpAsset(ParticleSystem particleSystem)\r\n        {\r\n            \r\n            if (particleSystem.shape.mesh == null)\r\n            {\r\n                return;\r\n            }\r\n\r\n            AppendObjRef(particleSystem.gameObject, particleSystem.shape.mesh, \"Mesh-Particle\");\r\n\r\n            var fbxPath = AssetDatabase.GetAssetPath(particleSystem.shape.mesh);\r\n            if (string.IsNullOrEmpty(fbxPath))\r\n            {\r\n                return;\r\n            }\r\n            \r\n            var fbxDepends = AssetDatabase.GetDependencies(fbxPath, true);\r\n            foreach (var dependAsset in fbxDepends)\r\n            {\r\n                var obj = AssetDatabase.LoadAssetAtPath&lt;UnityEngine.Object>(dependAsset);\r\n                Log.EditorInfo(dependAsset);\r\n                AppendObjRef(particleSystem.gameObject, obj, \"ParticleDepends\");\r\n            }\r\n        }\r\n\r\n        \/\/ \u6536\u96c6\u7c92\u5b50\u7cfb\u7edf\r\n        var particleSystems = prefab.GetComponentsInChildren&lt;ParticleSystem>(true);\r\n        foreach (var particleSystem in particleSystems)\r\n        {\r\n            var psr = particleSystem.GetComponent&lt;ParticleSystemRenderer>();\r\n            if (psr != null)\r\n            {\r\n                if (psr.sharedMaterial != null)\r\n                {\r\n                    AppendObjRef(particleSystem.gameObject, psr.sharedMaterial, \"Material-Particle\");\r\n                    try\r\n                    {\r\n                        AppendObjRef(particleSystem.gameObject, psr.sharedMaterial.mainTexture, \"MainTex-Particle\");\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n    \r\n                if (psr.trailMaterial != null)\r\n                {\r\n                    AppendObjRef(particleSystem.gameObject, psr.trailMaterial, \"Material-Trail\");\r\n                    try\r\n                    {\r\n                        AppendObjRef(particleSystem.gameObject, psr.trailMaterial.mainTexture, \"MainTex-Trail\");\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n\r\n                \/\/ \u6536\u96c6ParticleSystemRenderMode\u4e2d\u7684Meshs\r\n                if (psr.renderMode == ParticleSystemRenderMode.Mesh)\r\n                {\r\n                    Mesh&#91;] meshes = new Mesh&#91;psr.meshCount];\r\n                    psr.GetMeshes(meshes);\r\n                    for(int i=0; i&lt;meshes.Length; ++i)\r\n                    {\r\n                        AppendObjRef(particleSystem.gameObject, meshes&#91;i], \"Mesh-Particle\");\r\n                    }                    \r\n                }\r\n            }\r\n\r\n            AppendObjRef(particleSystem.gameObject, particleSystem.shape.texture, \"MainTex-Particle\");\r\n            AppendSharpAsset(particleSystem);\r\n        }\r\n\r\n        \/\/ \u6536\u96c6Mesh\r\n        var meshs = prefab.GetComponentsInChildren&lt;MeshFilter>(true);\r\n        foreach (var meshFilter in meshs)\r\n        {\r\n            AppendObjRef(meshFilter.gameObject, meshFilter.sharedMesh, \"Mesh-MeshFilter\");\r\n        }\r\n\r\n        \/\/ \u6536\u96c6VFXImage\r\n        var vfxImages = prefab.GetComponentsInChildren&lt;VFXImage>(true);\r\n        foreach (var vfxImage in vfxImages)\r\n        {\r\n            AppendObjRef(vfxImage.gameObject, vfxImage.CustomMesh, \"Mesh-VFXImage\");\r\n        }\r\n\r\n        \/\/ \u6536\u96c6\u52a8\u753b\r\n        var animators = prefab.GetComponentsInChildren&lt;Animator>(true);\r\n        foreach (var animator in animators)\r\n        {\r\n            if (animator.runtimeAnimatorController == null)\r\n            {\r\n                continue;\r\n            }\r\n\r\n            var ac = animator.runtimeAnimatorController as AnimatorController;\r\n            if (ac == null)\r\n            {\r\n                continue;\r\n            }\r\n\r\n            foreach (var layer in ac.layers)\r\n            {\r\n                foreach (var state in layer.stateMachine.states)\r\n                {\r\n                    if (state.state.motion == null)\r\n                    {\r\n                        continue;\r\n                    }\r\n\r\n                    \/\/ Anim\u52a8\u753b\r\n                    AppendObjRef(animator.gameObject, state.state.motion, \"AnimMotion\");\r\n                }\r\n            }\r\n            \r\n            \/\/ \u63a7\u5236\u5668\u6587\u4ef6\r\n            AppendObjRef(animator.gameObject, ac, \"AnimLayerMotion\");\r\n        }\r\n    }\r\n\r\n    private readonly static List&lt;string> unityDepExcludeExts = new List&lt;string>() { \".cs\", \".dll\", \".shader\" };\r\n\r\n    private static void CollectSelectPrefabAllDepends(string prefabAssetPath, Dictionary&lt;string, PrefabRefInfos> pool)\r\n    {\r\n        var depends = AssetDatabase.GetDependencies(prefabAssetPath);\r\n        foreach (var dependAsset in depends)\r\n        {\r\n            if (prefabAssetPath == dependAsset)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            var ext = System.IO.Path.GetExtension(dependAsset).ToLower();\r\n            if (unityDepExcludeExts.Contains(ext))\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            if (!pool.TryGetValue(dependAsset, out var info))\r\n            {\r\n                info = new PrefabRefInfos();\r\n                pool.Add(dependAsset, info);\r\n            }\r\n\r\n            info.AddRefInfo(prefabAssetPath, dependAsset, \"Unity\");\r\n        }\r\n    }\r\n\r\n    public static void CollectAndPreviewImages(Dictionary&lt;string, PrefabRefInfos> result, string prefabAssetPaths, bool useUnityDepends)\r\n    {\r\n        if (prefabAssetPaths.Length == 0)\r\n        {\r\n            return;\r\n        }\r\n\r\n        CollectFunc collectFunc = useUnityDepends ? CollectSelectPrefabAllDepends : CollectSelectPrefabAssets;\r\n\r\n        result.Clear();\r\n        var prefabAssetPathsList = prefabAssetPaths.Split(';');\r\n        foreach (var prefabAssetPath in prefabAssetPathsList)\r\n        {\r\n            collectFunc(prefabAssetPath, result);\r\n        }\r\n    }\r\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u4e00\u822c\u7684Prefab\u5f15\u7528\u67e5\u627e\u5de5\u5177\uff0c\u53ea\u80fd\u67e5\u627ePrefb\u5f15\u7528\u4e86\uff0c\u4f46\u662f\u54ea\u4e2a\u8282\u70b9\u5f15\u7528\u4e86\u4e0d\u77e5\u9053\uff0c\u4ee5\u4e0b\u5de5\u5177\u53ef\u4ee5\u7cbe\u786e\u5b9a\u4f4d\u662f\u54ea\u4e2a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/6290"}],"collection":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6290"}],"version-history":[{"count":2,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/6290\/revisions"}],"predecessor-version":[{"id":6292,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/6290\/revisions\/6292"}],"wp:attachment":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6290"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6290"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6290"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}