1083 lines
39 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class RenameHumanoidBones : EditorWindow
{
private Animator selectedAnimator;
private Dictionary<HumanBodyBones, Transform> humanoidBones = new Dictionary<HumanBodyBones, Transform>();
private Dictionary<HumanBodyBones, string> newBoneNames = new Dictionary<HumanBodyBones, string>();
[MenuItem("Tools/Humanoid Bone Renamer")]
public static void ShowWindow()
{
GetWindow<RenameHumanoidBones>("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<Animator>();
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<Transform, Transform> DetachBonesFromHierarchy()
{
Debug.Log("Detaching bones from hierarchy...");
Dictionary<Transform, Transform> originalParents = new Dictionary<Transform, Transform>();
// 모든 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<Transform, Transform> 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, string>
{
{ 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("믹사모 네이밍으로 일괄 변경 완료!");
}
}