#if UNITY_EDITOR using UnityEditor; using UnityEngine; using System.Collections.Generic; namespace Bitd { public class BlendshapeModifier : EditorWindow { private List gameObjects = new List(); // µå·¡±× ¾Ø µå·ÓÀ¸·Î ¹ÞÀº GameObject ¸ñ·Ï private Dictionary blendShapes = new Dictionary(); // ºí·»µå½¦ÀÌÇÁ À̸§°ú °ª private bool blendShapesLoaded = false; private Vector2 scrollPosObjects; // ¿ÀºêÁ§Æ® ¸ñ·Ï ½ºÅ©·Ñ À§Ä¡ private Vector2 scrollPosBlendShapes; // ºí·»µå½¦ÀÌÇÁ ¸ñ·Ï ½ºÅ©·Ñ À§Ä¡ [MenuItem("Bitd/ºí·»µå½¦ÀÌÇÁ Àϰý¼öÁ¤", false, 2)] public static void ShowWindow() { BlendshapeModifier window = GetWindow("ºí·»µå½¦ÀÌÇÁ ¼öÁ¤±â"); 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 keys = new List(blendShapes.Keys); List values = new List(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 sortedBlendShapes = new SortedDictionary(); foreach (GameObject obj in gameObjects) { if (obj == null) continue; List 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(sortedBlendShapes); } void ApplyBlendShapes() { Undo.IncrementCurrentGroup(); Undo.SetCurrentGroupName("Modify All Blendshapes"); foreach (GameObject obj in gameObjects) { if (obj == null) continue; List 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 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 FindAllSkinnedMeshRenderers(GameObject obj) { List skinnedMeshRenderers = new List(); // ºñȰ¼ºÈ­µÈ ¿ÀºêÁ§Æ®µµ Æ÷ÇÔÇÏ¿© ¸ðµç ¿ÀºêÁ§Æ® ¼öÁý 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(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