using UnityEngine; using UnityEditor; using System.IO; using System.Linq; public class SyncFBXMaterialToPrefab : Editor { [MenuItem("Assets/材质工具/同步 FBX 材质到对应 Prefab", true)] static bool Validate() { return Selection.assetGUIDs.Any(guid => AssetDatabase.GUIDToAssetPath(guid).EndsWith(".fbx")); } [MenuItem("Assets/材质工具/同步 FBX 材质到对应 Prefab")] static void SyncMaterialsFromFBX() { foreach (string guid in Selection.assetGUIDs) { string fbxPath = AssetDatabase.GUIDToAssetPath(guid); if (!fbxPath.EndsWith(".fbx")) continue; GameObject fbxModel = AssetDatabase.LoadAssetAtPath(fbxPath); if (fbxModel == null) continue; string prefabPath = Path.ChangeExtension(fbxPath, ".prefab"); prefabPath = prefabPath.Replace("Models", "Prefabs"); GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); if (prefab == null) { Debug.LogWarning($"未找到对应的 prefab: {prefabPath}"); continue; } // 获取 FBX 中当前 remap 的材质信息(用名字匹配 Renderer 路径) var fbxRenderers = fbxModel.GetComponentsInChildren(true); var fbxMatMap = fbxRenderers.ToDictionary( r => GetRelativePath(r.transform, fbxModel.transform), r => r.sharedMaterials ); GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab); bool hasChanged = false; foreach (var renderer in instance.GetComponentsInChildren(true)) { string path = GetRelativePath(renderer.transform, instance.transform); if (fbxMatMap.TryGetValue(path, out var remappedMats)) { renderer.sharedMaterials = remappedMats; hasChanged = true; Debug.Log($"✔ 替换 Renderer 材质: {path}"); } } if (hasChanged) { PrefabUtility.SaveAsPrefabAsset(instance, prefabPath); Debug.Log($"✅ 已同步材质到 Prefab: {prefabPath}"); } Object.DestroyImmediate(instance); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } static string GetRelativePath(Transform current, Transform root) { if (current == root) return current.name; return GetRelativePath(current.parent, root) + "/" + current.name; } }