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