using UnityEngine; using UnityEditor; using System.Collections.Generic; public class RenameHumanoidBones : EditorWindow { private Animator selectedAnimator; private Dictionary humanoidBones = new Dictionary(); private Dictionary newBoneNames = new Dictionary(); [MenuItem("Tools/Humanoid Bone Renamer")] public static void ShowWindow() { GetWindow("Humanoid Bone Renamer"); } private Vector2 scrollPosition; private void OnGUI() { GUILayout.Label("Humanoid Bone Renamer", EditorStyles.boldLabel); if (GUILayout.Button("Find Humanoid Bones")) { FindHumanoidBones(); } // 믹사모 네이밍으로 일괄 변경 버튼 추가 if (GUILayout.Button("믹사모 네이밍으로 일괄 변경")) { RenameToMixamo(); } if (selectedAnimator == null) { GUILayout.Label("No valid Humanoid Animator selected.", EditorStyles.helpBox); return; } GUILayout.Label("Selected GameObject: " + selectedAnimator.gameObject.name, EditorStyles.boldLabel); // T포즈 관련 버튼들 추가 EditorGUILayout.Space(); GUILayout.Label("T-Pose Functions", EditorStyles.boldLabel); if (GUILayout.Button("Check T-Pose Conditions")) { CheckTPoseConditions(); } if (GUILayout.Button("Apply Perfect T-Pose")) { ApplyPerfectTPose(); } if (GUILayout.Button("Reset to Default Pose")) { ResetToDefaultPose(); } EditorGUILayout.Space(); if (humanoidBones.Count > 0) { scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(400)); EditorGUILayout.BeginVertical("box"); GUILayout.Label("Humanoid Bones", EditorStyles.boldLabel); foreach (var bone in humanoidBones) { EditorGUILayout.BeginHorizontal(); // First column: Unity's Humanoid bone name GUILayout.Label(bone.Key.ToString(), GUILayout.Width(150)); // Second column: Current bone name GUILayout.Label(bone.Value != null ? bone.Value.name : "None", GUILayout.Width(150)); // Third column: Input field for new name (defaulting to the first column's name) if (!newBoneNames.ContainsKey(bone.Key)) { newBoneNames[bone.Key] = bone.Key.ToString(); } newBoneNames[bone.Key] = EditorGUILayout.TextField(newBoneNames[bone.Key], GUILayout.Width(150)); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); EditorGUILayout.EndScrollView(); } if (GUILayout.Button("Change Humanoid Bones Name")) { ChangeHumanoidBoneNames(); } } private void FindHumanoidBones() { selectedAnimator = null; humanoidBones.Clear(); newBoneNames.Clear(); if (Selection.activeGameObject == null) { Debug.LogError("No GameObject selected. Please select a GameObject with an Animator component."); return; } selectedAnimator = Selection.activeGameObject.GetComponent(); if (selectedAnimator == null || selectedAnimator.avatar == null || !selectedAnimator.avatar.isValid || !selectedAnimator.avatar.isHuman) { Debug.LogError("Selected GameObject does not have a valid Humanoid Avatar."); return; } for (int i = 0; i < HumanTrait.BoneCount; i++) { HumanBodyBones bone = (HumanBodyBones)i; Transform boneTransform = selectedAnimator.GetBoneTransform(bone); if (boneTransform != null) { humanoidBones[bone] = boneTransform; } } Debug.Log("Humanoid bones found and ready for renaming."); } private void ChangeHumanoidBoneNames() { if (selectedAnimator == null) { Debug.LogError("No valid Humanoid Animator selected."); return; } foreach (var bone in humanoidBones) { if (bone.Value != null && !string.IsNullOrWhiteSpace(newBoneNames[bone.Key])) { string newName = newBoneNames[bone.Key]; Debug.Log($"Renaming {bone.Value.name} to {newName}"); bone.Value.name = newName; } } Debug.Log("Bone renaming completed."); } // T포즈 조건 검증 private void CheckTPoseConditions() { if (selectedAnimator == null) { Debug.LogError("No valid Humanoid Animator selected."); return; } Debug.Log("=== T-Pose Conditions Check ==="); // 1. 몸통 뼈대들의 World X축 좌표가 0인지 확인 CheckBodyAlignment(); // 2. 팔 뼈대들의 World Z축 좌표가 동일한지 확인 CheckArmAlignment(); // 3. 다리 뼈대들의 World X축 좌표가 동일한지 확인 CheckLegAlignment(); Debug.Log("=== T-Pose Conditions Check Complete ==="); } private void CheckBodyAlignment() { Debug.Log("--- Body Alignment Check ---"); HumanBodyBones[] bodyBones = { HumanBodyBones.Hips, HumanBodyBones.Spine, HumanBodyBones.Chest, HumanBodyBones.UpperChest, HumanBodyBones.Neck, HumanBodyBones.Head }; float targetX = 0f; bool allAligned = true; foreach (var boneType in bodyBones) { Transform bone = selectedAnimator.GetBoneTransform(boneType); if (bone != null) { float worldX = bone.position.x; float difference = Mathf.Abs(worldX - targetX); Debug.Log($"{boneType}: World X = {worldX:F3} (Target: {targetX:F3}, Difference: {difference:F3})"); if (difference > 0.01f) { allAligned = false; Debug.LogWarning($" -> {boneType} is not aligned! Difference: {difference:F3}"); } } } if (allAligned) { Debug.Log("✓ Body bones are properly aligned on X-axis"); } else { Debug.LogWarning("✗ Body bones are NOT properly aligned on X-axis"); } } private void CheckArmAlignment() { Debug.Log("--- Arm Alignment Check ---"); HumanBodyBones[] leftArmBones = { HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand }; HumanBodyBones[] rightArmBones = { HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand }; CheckSideArmAlignment("Left Arm", leftArmBones); CheckSideArmAlignment("Right Arm", rightArmBones); } private void CheckSideArmAlignment(string sideName, HumanBodyBones[] armBones) { Debug.Log($"--- {sideName} Alignment Check ---"); float targetZ = 0f; bool firstBone = true; bool allAligned = true; foreach (var boneType in armBones) { Transform bone = selectedAnimator.GetBoneTransform(boneType); if (bone != null) { float worldZ = bone.position.z; if (firstBone) { targetZ = worldZ; firstBone = false; } float difference = Mathf.Abs(worldZ - targetZ); Debug.Log($"{boneType}: World Z = {worldZ:F3} (Target: {targetZ:F3}, Difference: {difference:F3})"); if (difference > 0.01f) { allAligned = false; Debug.LogWarning($" -> {boneType} is not aligned! Difference: {difference:F3}"); } } } if (allAligned) { Debug.Log($"✓ {sideName} bones are properly aligned on Z-axis"); } else { Debug.LogWarning($"✗ {sideName} bones are NOT properly aligned on Z-axis"); } } private void CheckLegAlignment() { Debug.Log("--- Leg Alignment Check ---"); HumanBodyBones[] leftLegBones = { HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes }; HumanBodyBones[] rightLegBones = { HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, HumanBodyBones.RightToes }; CheckSideLegAlignment("Left Leg", leftLegBones); CheckSideLegAlignment("Right Leg", rightLegBones); } private void CheckSideLegAlignment(string sideName, HumanBodyBones[] legBones) { Debug.Log($"--- {sideName} Alignment Check ---"); float targetX = 0f; bool firstBone = true; bool allAligned = true; foreach (var boneType in legBones) { Transform bone = selectedAnimator.GetBoneTransform(boneType); if (bone != null) { float worldX = bone.position.x; if (firstBone) { targetX = worldX; firstBone = false; } float difference = Mathf.Abs(worldX - targetX); Debug.Log($"{boneType}: World X = {worldX:F3} (Target: {targetX:F3}, Difference: {difference:F3})"); if (difference > 0.01f) { allAligned = false; Debug.LogWarning($" -> {boneType} is not aligned! Difference: {difference:F3}"); } } } if (allAligned) { Debug.Log($"✓ {sideName} bones are properly aligned on X-axis"); } else { Debug.LogWarning($"✗ {sideName} bones are NOT properly aligned on X-axis"); } } // 완벽한 T포즈 적용 private void ApplyPerfectTPose() { if (selectedAnimator == null) { Debug.LogError("No valid Humanoid Animator selected."); return; } Debug.Log("=== Applying Perfect T-Pose ==="); // Undo 시스템에 등록 Undo.RecordObject(selectedAnimator.gameObject, "Apply T-Pose"); // 단계 1: 팔 부분 조정 AdjustArmBones(); // 단계 2: 다리 부분 조정 AdjustLegBones(); Debug.Log("Perfect T-Pose applied successfully!"); } // 팔 뼈대 조정 (단계 1) private void AdjustArmBones() { Debug.Log("Adjusting arm bones..."); // 왼쪽 팔 AdjustSingleArm(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, "Left"); // 오른쪽 팔 AdjustSingleArm(HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, "Right"); } // 다리 뼈대 조정 (단계 2) private void AdjustLegBones() { Debug.Log("Adjusting leg bones..."); // 왼쪽 다리 AdjustSingleLeg(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, "Left"); // 오른쪽 다리 AdjustSingleLeg(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, "Right"); } private void AdjustSingleLeg(HumanBodyBones lowerLeg, HumanBodyBones foot, string side) { Debug.Log($"Adjusting {side} leg..."); // LowerLeg (무릎) 조정 Transform lowerLegBone = selectedAnimator.GetBoneTransform(lowerLeg); if (lowerLegBone != null) { // 로테이션은 건드리지 않음 (기존 회전값 유지) // 로컬 X, Z 포지션만 0으로 변경 Vector3 localPos = lowerLegBone.localPosition; localPos.x = 0f; localPos.z = 0f; lowerLegBone.localPosition = localPos; Debug.Log($"{side} LowerLeg - Local Rotation: {lowerLegBone.localRotation.eulerAngles}, Local Position: {lowerLegBone.localPosition}"); } // Foot (발목) 조정 Transform footBone = selectedAnimator.GetBoneTransform(foot); if (footBone != null) { // 로테이션은 건드리지 않음 (기존 회전값 유지) // 로컬 X, Z 포지션만 0으로 변경 Vector3 localPos = footBone.localPosition; localPos.x = 0f; localPos.z = 0f; footBone.localPosition = localPos; Debug.Log($"{side} Foot - Local Rotation: {footBone.localRotation.eulerAngles}, Local Position: {footBone.localPosition}"); } // 발가락 조정 AdjustToes(side); } private void AdjustToes(string side) { Debug.Log($"Adjusting {side} toes..."); HumanBodyBones toeBone; if (side == "Left") { toeBone = HumanBodyBones.LeftToes; } else // Right { toeBone = HumanBodyBones.RightToes; } Transform bone = selectedAnimator.GetBoneTransform(toeBone); if (bone != null) { // 로테이션은 건드리지 않음 (기존 회전값 유지) // 로컬 X, Z 포지션만 0으로 변경 Vector3 localPos = bone.localPosition; localPos.x = 0f; localPos.z = 0f; bone.localPosition = localPos; Debug.Log($"{side} Toes - Local Rotation: {bone.localRotation.eulerAngles}, Local Position: {bone.localPosition}"); } } private void AdjustSingleArm(HumanBodyBones upperArm, HumanBodyBones lowerArm, HumanBodyBones hand, string side) { Debug.Log($"Adjusting {side} arm..."); // UpperArm 조정 Transform upperArmBone = selectedAnimator.GetBoneTransform(upperArm); if (upperArmBone != null) { // 로컬 Rotation을 0,0,0으로 초기화 upperArmBone.localRotation = Quaternion.identity; // 로컬 X, Z 포지션을 0으로 변경 Vector3 localPos = upperArmBone.localPosition; localPos.x = 0f; localPos.z = 0f; upperArmBone.localPosition = localPos; Debug.Log($"{side} UpperArm - Local Rotation: {upperArmBone.localRotation.eulerAngles}, Local Position: {upperArmBone.localPosition}"); } // LowerArm 조정 Transform lowerArmBone = selectedAnimator.GetBoneTransform(lowerArm); if (lowerArmBone != null) { // 로컬 Rotation을 0,0,0으로 초기화 lowerArmBone.localRotation = Quaternion.identity; // 로컬 X, Z 포지션을 0으로 변경 Vector3 localPos = lowerArmBone.localPosition; localPos.x = 0f; localPos.z = 0f; lowerArmBone.localPosition = localPos; Debug.Log($"{side} LowerArm - Local Rotation: {lowerArmBone.localRotation.eulerAngles}, Local Position: {lowerArmBone.localPosition}"); } // Hand 조정 Transform handBone = selectedAnimator.GetBoneTransform(hand); if (handBone != null) { // 로컬 Rotation을 0,0,0으로 초기화 handBone.localRotation = Quaternion.identity; // 로컬 X, Z 포지션을 0으로 변경 Vector3 localPos = handBone.localPosition; localPos.x = 0f; localPos.z = 0f; handBone.localPosition = localPos; Debug.Log($"{side} Hand - Local Rotation: {handBone.localRotation.eulerAngles}, Local Position: {handBone.localPosition}"); } // 손가락 조정 (엄지손가락 제외) AdjustFingers(side); } private void AdjustFingers(string side) { Debug.Log($"Adjusting {side} fingers (excluding thumb)..."); // 엄지손가락을 제외한 손가락들 HumanBodyBones[] fingerBones; if (side == "Left") { fingerBones = new HumanBodyBones[] { HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal, HumanBodyBones.LeftMiddleProximal, HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal, HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal, HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal }; } else // Right { fingerBones = new HumanBodyBones[] { HumanBodyBones.RightIndexProximal, HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal, HumanBodyBones.RightMiddleProximal, HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal, HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal, HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal }; } foreach (var fingerBone in fingerBones) { Transform bone = selectedAnimator.GetBoneTransform(fingerBone); if (bone != null) { // 로컬 Rotation을 0,0,0으로 초기화 bone.localRotation = Quaternion.identity; // 손가락 첫 마디(Proximal)는 X축을 유지, 나머지는 X, Z 포지션을 0으로 변경 Vector3 localPos = bone.localPosition; if (fingerBone.ToString().Contains("Proximal")) { // 첫 마디는 X축 유지, Z축만 0으로 localPos.z = 0f; } else { // 두번째, 세번째 마디는 X, Z 모두 0으로 localPos.x = 0f; localPos.z = 0f; } bone.localPosition = localPos; Debug.Log($"{side} {fingerBone} - Local Rotation: {bone.localRotation.eulerAngles}, Local Position: {bone.localPosition}"); } } // 엄지손가락 두번째와 세번째 마디 조정 AdjustThumbFingers(side); } private void AdjustThumbFingers(string side) { Debug.Log($"Adjusting {side} thumb intermediate and distal..."); HumanBodyBones[] thumbBones; if (side == "Left") { thumbBones = new HumanBodyBones[] { HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal }; } else // Right { thumbBones = new HumanBodyBones[] { HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal }; } foreach (var thumbBone in thumbBones) { Transform bone = selectedAnimator.GetBoneTransform(thumbBone); if (bone != null) { // 로컬 Rotation을 0,0,0으로 초기화 bone.localRotation = Quaternion.identity; // X, Z 포지션을 0으로 변경 Vector3 localPos = bone.localPosition; localPos.x = 0f; localPos.z = 0f; bone.localPosition = localPos; Debug.Log($"{side} {thumbBone} - Local Rotation: {bone.localRotation.eulerAngles}, Local Position: {bone.localPosition}"); } } } // 뼈대들의 부모-자식 관계를 일시적으로 분리 private Dictionary DetachBonesFromHierarchy() { Debug.Log("Detaching bones from hierarchy..."); Dictionary originalParents = new Dictionary(); // 모든 Humanoid 뼈대의 부모-자식 관계를 저장하고 분리 for (int i = 0; i < HumanTrait.BoneCount; i++) { HumanBodyBones bone = (HumanBodyBones)i; Transform boneTransform = selectedAnimator.GetBoneTransform(bone); if (boneTransform != null) { // 원래 부모를 저장 originalParents[boneTransform] = boneTransform.parent; // 뼈대를 최상위 레벨로 이동 (계층구조에서 분리) boneTransform.SetParent(null, true); Debug.Log($"Detached {bone} from parent: {originalParents[boneTransform]?.name ?? "None"}"); } } Debug.Log($"Detached {originalParents.Count} bones from hierarchy"); return originalParents; } // 뼈대들을 원래 부모-자식 관계로 복원 private void RestoreBoneHierarchy(Dictionary originalParents) { Debug.Log("Restoring bone hierarchy..."); foreach (var kvp in originalParents) { Transform bone = kvp.Key; Transform originalParent = kvp.Value; if (bone != null) { // 원래 부모로 복원 bone.SetParent(originalParent, true); Debug.Log($"Restored {bone.name} to parent: {originalParent?.name ?? "None"}"); } } Debug.Log("Bone hierarchy restored"); } private void AlignBodyBones() { Debug.Log("Aligning body bones..."); HumanBodyBones[] bodyBones = { HumanBodyBones.Hips, HumanBodyBones.Spine, HumanBodyBones.Chest, HumanBodyBones.UpperChest, HumanBodyBones.Neck, HumanBodyBones.Head }; foreach (var boneType in bodyBones) { Transform bone = selectedAnimator.GetBoneTransform(boneType); if (bone != null) { // 현재 위치에서 X축만 0으로 조정 Vector3 newPosition = bone.position; newPosition.x = 0f; bone.position = newPosition; // 회전을 0으로 설정 (똑바로 서있음) bone.rotation = Quaternion.identity; Debug.Log($"Aligned {boneType} to X=0, rotation=0"); } } } private void SetArmsToTPose() { Debug.Log("Setting arms to T-pose..."); // 왼쪽 팔 SetArmToTPose(HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, true); // 오른쪽 팔 SetArmToTPose(HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, false); } private void SetArmToTPose(HumanBodyBones shoulder, HumanBodyBones upperArm, HumanBodyBones lowerArm, HumanBodyBones hand, bool isLeft) { string side = isLeft ? "Left" : "Right"; // 어깨 위치 및 회전 조정 Transform shoulderBone = selectedAnimator.GetBoneTransform(shoulder); if (shoulderBone != null) { // 어깨를 몸통 중심에서 적절한 거리로 이동 Vector3 shoulderPos = shoulderBone.position; float shoulderOffset = isLeft ? -0.3f : 0.3f; shoulderPos.x = shoulderOffset; shoulderBone.position = shoulderPos; // 어깨를 Z축 기준으로 회전하여 팔이 수평이 되도록 함 float shoulderZRotation = isLeft ? 90f : -90f; shoulderBone.rotation = Quaternion.Euler(0, 0, shoulderZRotation); Debug.Log($"Positioned {side} shoulder at X={shoulderOffset}, Z rotation={shoulderZRotation}°"); } // 상완 위치 및 회전 조정 Transform upperArmBone = selectedAnimator.GetBoneTransform(upperArm); if (upperArmBone != null) { // 상완을 어깨에서 수평으로 뻗도록 위치 조정 Vector3 upperArmPos = upperArmBone.position; float armLength = Vector3.Distance(shoulderBone.position, upperArmBone.position); upperArmPos.x = isLeft ? -armLength : armLength; upperArmBone.position = upperArmPos; // 상완을 완전히 펴기 위해 회전 조정 upperArmBone.rotation = Quaternion.identity; Debug.Log($"Positioned {side} upper arm at X={upperArmPos.x}, rotation=0°"); } // 하완 위치 및 회전 조정 Transform lowerArmBone = selectedAnimator.GetBoneTransform(lowerArm); if (lowerArmBone != null) { // 하완을 상완에서 수평으로 뻗도록 위치 조정 Vector3 lowerArmPos = lowerArmBone.position; float forearmLength = Vector3.Distance(upperArmBone.position, lowerArmBone.position); lowerArmPos.x = isLeft ? -(upperArmBone.position.x + forearmLength) : (upperArmBone.position.x + forearmLength); lowerArmBone.position = lowerArmPos; // 하완을 완전히 펴기 위해 회전 조정 lowerArmBone.rotation = Quaternion.identity; Debug.Log($"Positioned {side} lower arm at X={lowerArmPos.x}, rotation=0°"); } // 손 위치 및 회전 조정 Transform handBone = selectedAnimator.GetBoneTransform(hand); if (handBone != null) { // 손을 하완에서 수평으로 뻗도록 위치 조정 Vector3 handPos = handBone.position; float handLength = Vector3.Distance(lowerArmBone.position, handBone.position); handPos.x = isLeft ? -(lowerArmBone.position.x + handLength) : (lowerArmBone.position.x + handLength); handBone.position = handPos; // 손을 자연스럽게 펴기 위해 회전 조정 handBone.rotation = Quaternion.identity; Debug.Log($"Positioned {side} hand at X={handPos.x}, rotation=0°"); } } private void AlignLegBones() { Debug.Log("Aligning leg bones..."); HumanBodyBones[] leftLegBones = { HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes }; HumanBodyBones[] rightLegBones = { HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, HumanBodyBones.RightToes }; AlignSideLegBones("Left", leftLegBones, -0.2f); AlignSideLegBones("Right", rightLegBones, 0.2f); } private void AlignSideLegBones(string side, HumanBodyBones[] legBones, float targetX) { foreach (var boneType in legBones) { Transform bone = selectedAnimator.GetBoneTransform(boneType); if (bone != null) { // 위치를 목표 X축으로 조정 Vector3 newPosition = bone.position; newPosition.x = targetX; bone.position = newPosition; // 다리 뼈대들을 똑바로 세우기 위해 회전 조정 bone.rotation = Quaternion.identity; Debug.Log($"Aligned {boneType} to X={targetX:F3}, rotation=0°"); } } } private void SetFingersAndToesToTPose() { Debug.Log("Setting fingers and toes to T-pose..."); // 손가락 설정 (완전히 펴짐) SetFingersToTPose(true); // 왼쪽 SetFingersToTPose(false); // 오른쪽 // 발가락 설정 (자연스러운 상태) SetToesToTPose(true); // 왼쪽 SetToesToTPose(false); // 오른쪽 } private void SetFingersToTPose(bool isLeft) { string side = isLeft ? "Left" : "Right"; // 모든 손가락 관절을 0도로 설정 for (int finger = 0; finger < 5; finger++) { for (int joint = 0; joint < 3; joint++) { HumanBodyBones fingerBone = GetFingerBone(isLeft, finger, joint); if (fingerBone != HumanBodyBones.LastBone) { Transform bone = selectedAnimator.GetBoneTransform(fingerBone); if (bone != null) { bone.localRotation = Quaternion.identity; } } } } Debug.Log($"Set {side} fingers to straight position"); } private void SetToesToTPose(bool isLeft) { string side = isLeft ? "Left" : "Right"; // 발가락을 자연스러운 상태로 설정 HumanBodyBones toeBone = isLeft ? HumanBodyBones.LeftToes : HumanBodyBones.RightToes; Transform bone = selectedAnimator.GetBoneTransform(toeBone); if (bone != null) { bone.localRotation = Quaternion.identity; Debug.Log($"Set {side} toes to natural position"); } } private HumanBodyBones GetFingerBone(bool isLeft, int finger, int joint) { if (finger == 0) // 엄지 { if (isLeft) { switch (joint) { case 0: return HumanBodyBones.LeftThumbProximal; case 1: return HumanBodyBones.LeftThumbIntermediate; case 2: return HumanBodyBones.LeftThumbDistal; } } else { switch (joint) { case 0: return HumanBodyBones.RightThumbProximal; case 1: return HumanBodyBones.RightThumbIntermediate; case 2: return HumanBodyBones.RightThumbDistal; } } } else // 나머지 손가락들 { if (isLeft) { switch (finger) { case 1: return joint == 0 ? HumanBodyBones.LeftIndexProximal : joint == 1 ? HumanBodyBones.LeftIndexIntermediate : HumanBodyBones.LeftIndexDistal; case 2: return joint == 0 ? HumanBodyBones.LeftMiddleProximal : joint == 1 ? HumanBodyBones.LeftMiddleIntermediate : HumanBodyBones.LeftMiddleDistal; case 3: return joint == 0 ? HumanBodyBones.LeftRingProximal : joint == 1 ? HumanBodyBones.LeftRingIntermediate : HumanBodyBones.LeftRingDistal; case 4: return joint == 0 ? HumanBodyBones.LeftLittleProximal : joint == 1 ? HumanBodyBones.LeftLittleIntermediate : HumanBodyBones.LeftLittleDistal; } } else { switch (finger) { case 1: return joint == 0 ? HumanBodyBones.RightIndexProximal : joint == 1 ? HumanBodyBones.RightIndexIntermediate : HumanBodyBones.RightIndexDistal; case 2: return joint == 0 ? HumanBodyBones.RightMiddleProximal : joint == 1 ? HumanBodyBones.RightMiddleIntermediate : HumanBodyBones.RightMiddleDistal; case 3: return joint == 0 ? HumanBodyBones.RightRingProximal : joint == 1 ? HumanBodyBones.RightRingIntermediate : HumanBodyBones.RightRingDistal; case 4: return joint == 0 ? HumanBodyBones.RightLittleProximal : joint == 1 ? HumanBodyBones.RightLittleIntermediate : HumanBodyBones.RightLittleDistal; } } } return HumanBodyBones.LastBone; // 유효하지 않은 경우 } // 기본 포즈로 리셋 private void ResetToDefaultPose() { if (selectedAnimator == null) { Debug.LogError("No valid Humanoid Animator selected."); return; } Debug.Log("=== Resetting to Default Pose ==="); // Undo 시스템에 등록 Undo.RecordObject(selectedAnimator.gameObject, "Reset to Default Pose"); // 모든 뼈대의 로컬 회전을 0으로 리셋 for (int i = 0; i < HumanTrait.BoneCount; i++) { HumanBodyBones bone = (HumanBodyBones)i; Transform boneTransform = selectedAnimator.GetBoneTransform(bone); if (boneTransform != null) { boneTransform.localRotation = Quaternion.identity; } } Debug.Log("Reset to default pose completed!"); } // 믹사모 네이밍 매핑 및 일괄 변경 함수 추가 private void RenameToMixamo() { if (selectedAnimator == null) { Debug.LogError("No valid Humanoid Animator selected."); return; } // HumanBodyBones와 믹사모 네이밍 매핑 var mixamoMap = new Dictionary { { HumanBodyBones.Hips, "mixamorig:Hips" }, { HumanBodyBones.LeftUpperLeg, "mixamorig:LeftUpLeg" }, { HumanBodyBones.LeftLowerLeg, "mixamorig:LeftLeg" }, { HumanBodyBones.LeftFoot, "mixamorig:LeftFoot" }, { HumanBodyBones.LeftToes, "mixamorig:LeftToeBase" }, { HumanBodyBones.RightUpperLeg, "mixamorig:RightUpLeg" }, { HumanBodyBones.RightLowerLeg, "mixamorig:RightLeg" }, { HumanBodyBones.RightFoot, "mixamorig:RightFoot" }, { HumanBodyBones.RightToes, "mixamorig:RightToeBase" }, { HumanBodyBones.Spine, "mixamorig:Spine" }, { HumanBodyBones.Chest, "mixamorig:Spine1" }, { HumanBodyBones.UpperChest, "mixamorig:Spine2" }, // UpperChest는 있는 경우만 { HumanBodyBones.Neck, "mixamorig:Neck" }, { HumanBodyBones.Head, "mixamorig:Head" }, { HumanBodyBones.LeftShoulder, "mixamorig:LeftShoulder" }, { HumanBodyBones.LeftUpperArm, "mixamorig:LeftArm" }, { HumanBodyBones.LeftLowerArm, "mixamorig:LeftForeArm" }, { HumanBodyBones.LeftHand, "mixamorig:LeftHand" }, { HumanBodyBones.RightShoulder, "mixamorig:RightShoulder" }, { HumanBodyBones.RightUpperArm, "mixamorig:RightArm" }, { HumanBodyBones.RightLowerArm, "mixamorig:RightForeArm" }, { HumanBodyBones.RightHand, "mixamorig:RightHand" }, // 왼손 손가락 { HumanBodyBones.LeftThumbProximal, "mixamorig:LeftHandThumb1" }, { HumanBodyBones.LeftThumbIntermediate, "mixamorig:LeftHandThumb2" }, { HumanBodyBones.LeftThumbDistal, "mixamorig:LeftHandThumb3" }, // mixamo에는 Thumb4가 있으나, Unity에는 없음 { HumanBodyBones.LeftIndexProximal, "mixamorig:LeftHandIndex1" }, { HumanBodyBones.LeftIndexIntermediate, "mixamorig:LeftHandIndex2" }, { HumanBodyBones.LeftIndexDistal, "mixamorig:LeftHandIndex3" }, { HumanBodyBones.LeftMiddleProximal, "mixamorig:LeftHandMiddle1" }, { HumanBodyBones.LeftMiddleIntermediate, "mixamorig:LeftHandMiddle2" }, { HumanBodyBones.LeftMiddleDistal, "mixamorig:LeftHandMiddle3" }, { HumanBodyBones.LeftRingProximal, "mixamorig:LeftHandRing1" }, { HumanBodyBones.LeftRingIntermediate, "mixamorig:LeftHandRing2" }, { HumanBodyBones.LeftRingDistal, "mixamorig:LeftHandRing3" }, { HumanBodyBones.LeftLittleProximal, "mixamorig:LeftHandPinky1" }, { HumanBodyBones.LeftLittleIntermediate, "mixamorig:LeftHandPinky2" }, { HumanBodyBones.LeftLittleDistal, "mixamorig:LeftHandPinky3" }, // 오른손 손가락 { HumanBodyBones.RightThumbProximal, "mixamorig:RightHandThumb1" }, { HumanBodyBones.RightThumbIntermediate, "mixamorig:RightHandThumb2" }, { HumanBodyBones.RightThumbDistal, "mixamorig:RightHandThumb3" }, { HumanBodyBones.RightIndexProximal, "mixamorig:RightHandIndex1" }, { HumanBodyBones.RightIndexIntermediate, "mixamorig:RightHandIndex2" }, { HumanBodyBones.RightIndexDistal, "mixamorig:RightHandIndex3" }, { HumanBodyBones.RightMiddleProximal, "mixamorig:RightHandMiddle1" }, { HumanBodyBones.RightMiddleIntermediate, "mixamorig:RightHandMiddle2" }, { HumanBodyBones.RightMiddleDistal, "mixamorig:RightHandMiddle3" }, { HumanBodyBones.RightRingProximal, "mixamorig:RightHandRing1" }, { HumanBodyBones.RightRingIntermediate, "mixamorig:RightHandRing2" }, { HumanBodyBones.RightRingDistal, "mixamorig:RightHandRing3" }, { HumanBodyBones.RightLittleProximal, "mixamorig:RightHandPinky1" }, { HumanBodyBones.RightLittleIntermediate, "mixamorig:RightHandPinky2" }, { HumanBodyBones.RightLittleDistal, "mixamorig:RightHandPinky3" }, }; // UpperChest가 없는 경우 무시 foreach (var kvp in mixamoMap) { if (kvp.Key == HumanBodyBones.UpperChest) { var upperChest = selectedAnimator.GetBoneTransform(HumanBodyBones.UpperChest); if (upperChest == null) continue; upperChest.name = kvp.Value; Debug.Log($"UpperChest 본이 있어 이름을 {kvp.Value}로 변경"); continue; } var bone = selectedAnimator.GetBoneTransform(kvp.Key); if (bone != null) { bone.name = kvp.Value; Debug.Log($"{kvp.Key} 이름을 {kvp.Value}로 변경"); } } Debug.Log("믹사모 네이밍으로 일괄 변경 완료!"); } }