Net.Like.Xue.Tokyo/Packages-Local/Net.BITKit.Bounds.Unity/SyncFBXMaterialToPrefab.cs

76 lines
2.6 KiB
C#

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<GameObject>(fbxPath);
if (fbxModel == null) continue;
string prefabPath = Path.ChangeExtension(fbxPath, ".prefab");
prefabPath = prefabPath.Replace("Models", "Prefabs");
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (prefab == null)
{
Debug.LogWarning($"未找到对应的 prefab: {prefabPath}");
continue;
}
// 获取 FBX 中当前 remap 的材质信息(用名字匹配 Renderer 路径)
var fbxRenderers = fbxModel.GetComponentsInChildren<Renderer>(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<Renderer>(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;
}
}