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

261 lines
9.7 KiB
C#

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
namespace Bitd
{
public class BlendshapeModifier : EditorWindow
{
private List<GameObject> gameObjects = new List<GameObject>(); // 드래그 앤 드롭으로 받은 GameObject 목록
private Dictionary<string, float> blendShapes = new Dictionary<string, float>(); // 블렌드쉐이프 이름과 값
private bool blendShapesLoaded = false;
private Vector2 scrollPosObjects; // 오브젝트 목록 스크롤 위치
private Vector2 scrollPosBlendShapes; // 블렌드쉐이프 목록 스크롤 위치
[MenuItem("Bitd/블렌드쉐이프 일괄수정", false, 2)]
public static void ShowWindow()
{
BlendshapeModifier window = GetWindow<BlendshapeModifier>("블렌드쉐이프 수정기");
window.position = new Rect(100, 100, 400, 900);
}
void OnGUI()
{
GUILayout.Label("아래에 게임오브젝트들을 넣어주세요", EditorStyles.boldLabel);
GUILayout.Label("모든 오브젝트에서 블렌드쉐이프의 값을 불러와 일괄 수정합니다.", EditorStyles.helpBox);
// 드래그 앤 드롭 구역 생성
GUILayout.Space(10);
EditorGUILayout.HelpBox("드래그 앤 드롭으로 게임 오브젝트를 추가하세요", MessageType.Info);
Rect dropArea = GUILayoutUtility.GetRect(0, 50, GUILayout.ExpandWidth(true));
GUI.Box(dropArea, "여기에 드래그하세요", EditorStyles.helpBox);
HandleDragAndDrop(dropArea);
// 드래그된 게임 오브젝트 리스트 표시
GUILayout.Label("추가된 게임오브젝트:", EditorStyles.boldLabel);
scrollPosObjects = EditorGUILayout.BeginScrollView(scrollPosObjects, GUILayout.Height(100)); // 최대 높이 제한
foreach (var go in gameObjects)
{
EditorGUILayout.ObjectField(go, typeof(GameObject), true);
}
EditorGUILayout.EndScrollView();
GUILayout.Space(10);
// 블렌드쉐이프 가져오기 버튼
if (GUILayout.Button("블렌드쉐이프 가져오기"))
{
LoadBlendShapes();
}
// 불러온 블렌드쉐이프 목록 표시
if (blendShapesLoaded)
{
GUILayout.Space(10);
GUILayout.Label("블렌드쉐이프 값 설정:", EditorStyles.boldLabel);
scrollPosBlendShapes = EditorGUILayout.BeginScrollView(scrollPosBlendShapes, GUILayout.Height(500)); // 스크롤뷰 시작
// Dictionary의 키와 값을 복사하여 사용
List<string> keys = new List<string>(blendShapes.Keys);
List<float> values = new List<float>(blendShapes.Values);
for (int i = 0; i < keys.Count; i++)
{
values[i] = EditorGUILayout.Slider(keys[i], values[i], 0f, 100f);
}
// 변경된 값을 다시 Dictionary에 업데이트
for (int i = 0; i < keys.Count; i++)
{
blendShapes[keys[i]] = values[i];
}
EditorGUILayout.EndScrollView(); // 스크롤뷰 종료
GUILayout.Space(10);
// 블렌드쉐이프 수정하기 버튼
if (GUILayout.Button("블렌드쉐이프 수정하기"))
{
ApplyBlendShapes();
}
}
}
// 드래그 앤 드롭 처리
void HandleDragAndDrop(Rect dropArea)
{
Event evt = Event.current;
switch (evt.type)
{
case EventType.DragUpdated:
case EventType.DragPerform:
if (!dropArea.Contains(evt.mousePosition))
return;
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (evt.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
foreach (Object draggedObject in DragAndDrop.objectReferences)
{
if (draggedObject is GameObject)
{
gameObjects.Add((GameObject)draggedObject); // 게임 오브젝트 추가
}
}
evt.Use();
}
break;
}
}
// 블렌드쉐이프를 가져오는 함수
void LoadBlendShapes()
{
blendShapes.Clear(); // 기존 데이터를 초기화
blendShapesLoaded = true;
SortedDictionary<string, float> sortedBlendShapes = new SortedDictionary<string, float>();
foreach (GameObject obj in gameObjects)
{
if (obj == null) continue;
List<SkinnedMeshRenderer> skinnedMeshRenderers = FindAllSkinnedMeshRenderers(obj);
foreach (SkinnedMeshRenderer skinnedMeshRenderer in skinnedMeshRenderers)
{
if (skinnedMeshRenderer == null) continue;
Mesh mesh = skinnedMeshRenderer.sharedMesh;
if (mesh == null) continue;
for (int i = 0; i < mesh.blendShapeCount; i++)
{
string blendShapeName = mesh.GetBlendShapeName(i);
// 중복되지 않는 블렌드쉐이프 이름만 추가
if (!sortedBlendShapes.ContainsKey(blendShapeName))
{
sortedBlendShapes.Add(blendShapeName, skinnedMeshRenderer.GetBlendShapeWeight(i));
}
}
}
}
// 정렬된 블렌드쉐이프를 Dictionary에 복사
blendShapes = new Dictionary<string, float>(sortedBlendShapes);
}
void ApplyBlendShapes()
{
Undo.IncrementCurrentGroup();
Undo.SetCurrentGroupName("Modify All Blendshapes");
foreach (GameObject obj in gameObjects)
{
if (obj == null) continue;
List<SkinnedMeshRenderer> skinnedMeshRenderers = FindAllSkinnedMeshRenderers(obj);
foreach (SkinnedMeshRenderer skinnedMeshRenderer in skinnedMeshRenderers)
{
if (skinnedMeshRenderer == null) continue;
Undo.RecordObject(skinnedMeshRenderer, "Modify Blendshape");
Mesh mesh = skinnedMeshRenderer.sharedMesh;
if (mesh == null) continue;
foreach (var blendShape in blendShapes)
{
int blendShapeIndex = mesh.GetBlendShapeIndex(blendShape.Key);
if (blendShapeIndex != -1 && skinnedMeshRenderer.GetBlendShapeWeight(blendShapeIndex) != blendShape.Value)
{
skinnedMeshRenderer.SetBlendShapeWeight(blendShapeIndex, blendShape.Value);
Debug.Log($"{obj.name}의 {blendShape.Key} 블렌드쉐이프가 {blendShape.Value}으로 설정되었습니다!");
}
}
EditorUtility.SetDirty(skinnedMeshRenderer);
}
}
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
}
//void ModifyBlendShapes()
//{
// foreach (GameObject obj in gameObjects)
// {
// if (obj == null) continue;
// // SkinnedMeshRenderer 컴포넌트를 가진 오브젝트 찾기
// List<SkinnedMeshRenderer> skinnedMeshRenderers = FindAllSkinnedMeshRenderers(obj);
// foreach (SkinnedMeshRenderer skinnedMeshRenderer in skinnedMeshRenderers)
// {
// if (skinnedMeshRenderer != null)
// {
// Mesh mesh = skinnedMeshRenderer.sharedMesh;
// // 블렌드쉐이프 인덱스 찾기
// int blendShapeIndex = FindBlendShapeIndex(mesh, blendshapeName);
// if (blendShapeIndex != -1)
// {
// // 블렌드쉐이프 값 변경
// skinnedMeshRenderer.SetBlendShapeWeight(blendShapeIndex, blendshapeValue);
// Debug.Log($"{obj.name}에 있는 {blendshapeName}(이)가 {blendshapeValue}으로 수정되었음!");
// }
// }
// }
// }
//}
List<SkinnedMeshRenderer> FindAllSkinnedMeshRenderers(GameObject obj)
{
List<SkinnedMeshRenderer> skinnedMeshRenderers = new List<SkinnedMeshRenderer>();
// 비활성화된 오브젝트도 포함하여 모든 오브젝트 수집
Object[] allObjects = EditorUtility.CollectDeepHierarchy(new Object[] { obj });
// 각 오브젝트에서 SkinnedMeshRenderer 컴포넌트 추출
foreach (Object o in allObjects)
{
if (o is GameObject)
{
GameObject go = (GameObject)o;
SkinnedMeshRenderer[] renderers = go.GetComponentsInChildren<SkinnedMeshRenderer>(true); // true를 사용해 비활성화된 자식까지 포함
skinnedMeshRenderers.AddRange(renderers);
}
}
return skinnedMeshRenderers;
}
// 블렌드쉐이프의 인덱스를 찾는 함수
int FindBlendShapeIndex(Mesh mesh, string blendShapeName)
{
if (mesh == null) return -1;
// 블렌드쉐이프 이름으로 인덱스 찾기
for (int i = 0; i < mesh.blendShapeCount; i++)
{
if (mesh.GetBlendShapeName(i) == blendShapeName)
{
return i;
}
}
return -1; // 해당 블렌드쉐이프가 없을 경우 -1 반환
}
}
}
#endif