2025-06-08 00:55:10 +09:00

274 lines
9.7 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace Bitd
{
public struct sRendererInfo
{
public Renderer RendererRef; // Renderer 참조
public int MaterialIndex; // Materials 배열에서의 인덱스
// 생성자 정의 (편리하게 초기화할 수 있도록)
public sRendererInfo(Renderer rendererRef, int materialIndex)
{
MaterialIndex = materialIndex;
RendererRef = rendererRef;
}
}
public class MatsReplacerWindow : EditorWindow
{
private GameObject targetPrefab;
private GameObject previousTargetPrefab;
private List<Material> uniqueMaterials;
private List<List<Renderer>> uniqueRenderers;
private List<string> materialUsage;
private List<Material> newMaterials;
private List<Material> previousNewMaterials;
private Dictionary<Renderer, Material[]> uniqueMaterialSetting;
private Dictionary<Material, List<sRendererInfo>> materialGroupWithInfo;
private bool applyClicked = false;
private int undoGroup = 0;
[MenuItem("Bitd/(돚)머티리얼 인식기", false, 252)]
public static void ShowWindow()
{
var window = GetWindow<MatsReplacerWindow>("Mats Replacer");
window.minSize = new Vector2(600, 300);
}
void OnGUI()
{
GUILayout.Label("머티리얼을 재배치합니다", EditorStyles.boldLabel);
targetPrefab = (GameObject)EditorGUILayout.ObjectField("타겟 부모 오브젝트", targetPrefab, typeof(GameObject), true);
// targetPrefab이 변경되었는지 확인
if (targetPrefab != previousTargetPrefab)
{
previousTargetPrefab = targetPrefab;
InitializeMaterials();
}
if (targetPrefab != null)
{
if (uniqueMaterials == null || uniqueMaterials.Count == 0)
{
InitializeMaterials();
}
// UI에서 각 마테리얼 필드 생성
for (int i = 0; i < uniqueMaterials.Count; i++)
{
GUILayout.Label($"사용처: {materialUsage[i]}", EditorStyles.label);
EditorGUILayout.BeginHorizontal();
// 왼쪽: 기존 머티리얼 (읽기 전용)
GUI.enabled = false; // 읽기 전용 상태로 전환
EditorGUILayout.ObjectField(uniqueMaterials[i], typeof(Material), false, GUILayout.Width(150));
GUI.enabled = true; // 다시 활성화
// 화살표 추가
GUILayout.Label("→", GUILayout.Width(20), GUILayout.ExpandWidth(false));
// 오른쪽: 새 머티리얼
newMaterials[i] = (Material)EditorGUILayout.ObjectField(newMaterials[i], typeof(Material), true);
EditorGUILayout.EndHorizontal();
}
if (!AreMaterialListsEqual(newMaterials, previousNewMaterials))
{
PreviewReplaceMaterials(targetPrefab.GetComponentsInChildren<Renderer>());
previousNewMaterials = new List<Material>(newMaterials);
}
if (GUILayout.Button("Replace Materials"))
{
ReplaceMaterials(targetPrefab.GetComponentsInChildren<Renderer>());
}
}
else
{
GUILayout.Label("Please select a target prefab.");
}
}
void InitializeMaterials()
{
if (targetPrefab == null) return;
Debug.Log("InitializeMaterials");
if (undoGroup > 0)
{
// Undo 그룹 끝
Undo.CollapseUndoOperations(undoGroup);
undoGroup = 0;
}
applyClicked = false;
materialGroupWithInfo = new Dictionary<Material, List<sRendererInfo>>();
Renderer[] renderers = targetPrefab.GetComponentsInChildren<Renderer>();
Dictionary<Material, List<string>> materialUsageDict = new Dictionary<Material, List<string>>();
uniqueMaterialSetting = new Dictionary<Renderer, Material[]>();
foreach (var renderer in renderers)
{
uniqueMaterialSetting.Add(renderer, renderer.sharedMaterials);
for (int i = 0; i < renderer.sharedMaterials.Length; i++)
{
Material material = renderer.sharedMaterials[i];
if (material != null)
{
if (!materialUsageDict.ContainsKey(material))
{
materialUsageDict[material] = new List<string>();
materialGroupWithInfo[material] = new List<sRendererInfo>();
}
materialUsageDict[material].Add(renderer.gameObject.name);
materialGroupWithInfo[material].Add(new sRendererInfo(renderer, i));
}
}
}
uniqueMaterials = new List<Material>(materialUsageDict.Keys);
uniqueRenderers = new List<List<Renderer>>();
for (int i = 0; i < uniqueMaterials.Count; i++)
{
uniqueRenderers.Add(new List<Renderer>());
}
materialUsage = new List<string>();
for (int i = 0; i < uniqueMaterials.Count; i++)
{
materialUsage.Add(string.Join(", ", materialUsageDict[uniqueMaterials[i]]));
}
newMaterials = new List<Material>(uniqueMaterials);
previousNewMaterials = new List<Material>(newMaterials);
// Undo 그룹 시작
Undo.IncrementCurrentGroup();
undoGroup = Undo.GetCurrentGroup();
}
void ReplaceMaterials(Renderer[] renderers)
{
foreach (var renderer in renderers)
{
// Renderer 컴포넌트를 Undo 기록
Undo.RecordObject(renderer, "Replace Materials");
// 기존 sharedMaterials 배열 복사
Material[] materials = uniqueMaterialSetting[renderer].Clone() as Material[];
if (materials == null) continue;
for (int i = 0; i < materials.Length; i++)
{
foreach (var materialRef in materialGroupWithInfo.Keys)
{
if (materials[i] == materialRef)
{
int index = uniqueMaterials.IndexOf(materialRef);
if (index >= 0)
{
materials[i] = newMaterials[index]; // 새 마테리얼로 교체
}
}
}
}
renderer.sharedMaterials = materials; // 수정된 마테리얼 배열을 다시 할당
}
if (targetPrefab != null)
{
Undo.RecordObject(targetPrefab, "Replace Materials");
EditorUtility.SetDirty(targetPrefab);
}
// Undo 그룹 끝
Undo.CollapseUndoOperations(undoGroup);
applyClicked = true;
// 알림창을 띄운 후 윈도우 닫기
EditorUtility.DisplayDialog("Mats Replacer", "성공적으로 변환되었습니다.", "OK");
Close();
}
void PreviewReplaceMaterials(Renderer[] renderers)
{
Debug.Log("PreviewReplaceMaterials");
foreach (var renderer in renderers)
{
// Renderer 컴포넌트를 Undo 기록
Undo.RecordObject(renderer, "Replace Materials");
// 기존 sharedMaterials 배열 복사
Material[] materials = uniqueMaterialSetting[renderer].Clone() as Material[];
if (materials == null) continue;
for (int i = 0; i < materials.Length; i++)
{
foreach (var materialRef in materialGroupWithInfo.Keys)
{
if (materials[i] == materialRef)
{
int index = uniqueMaterials.IndexOf(materialRef);
if (index >= 0)
{
materials[i] = newMaterials[index]; // 새 마테리얼로 교체
}
}
}
}
renderer.sharedMaterials = materials; // 수정된 마테리얼 배열을 다시 할당
}
Undo.RecordObject(targetPrefab, "Replace Materials");
EditorUtility.SetDirty(targetPrefab);
}
bool AreMaterialListsEqual(List<Material> list1, List<Material> list2)
{
if (list1 == null || list2 == null || list1.Count != list2.Count)
{
return false;
}
for (int i = 0; i < list1.Count; i++)
{
if (list1[i] != list2[i])
{
return false;
}
}
return true;
}
private void OnDisable()
{
if (!applyClicked)
{
foreach (var setting in uniqueMaterialSetting)
{
setting.Key.sharedMaterials = setting.Value;
}
if (undoGroup > 0)
{
Undo.RevertAllDownToGroup(undoGroup);
}
}
}
}
}
#endif