274 lines
9.7 KiB
C#
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 |