using UnityEngine; [DefaultExecutionOrder(16001)] public class SimplePoseTransfer : MonoBehaviour { [Header("Pose Transfer Settings")] public Animator sourceBone; public Animator[] targetBones; // 캐싱된 Transform들 private Transform[] cachedSourceBones; private Transform[,] cachedTargetBones; // 각 targetBone의 초기 회전 차이를 저장 private Quaternion[,] boneRotationDifferences; private void Start() { Init(); } public void Init() { if (targetBones == null || targetBones.Length == 0) { Debug.LogError("Target bones are null or empty"); return; } if (sourceBone == null) { Debug.LogError("Source bone is null"); return; } InitializeTargetBones(); CacheAllBoneTransforms(); Debug.Log($"SimplePoseTransfer initialized with {targetBones.Length} targets"); } private void InitializeTargetBones() { boneRotationDifferences = new Quaternion[targetBones.Length, 55]; for (int i = 0; i < targetBones.Length; i++) { if (targetBones[i] == null) { Debug.LogError($"targetBones[{i}] is null"); continue; } // 55개의 휴머노이드 본에 대해 회전 차이 계산 for (int j = 0; j < 55; j++) { Transform sourceBoneTransform = sourceBone.GetBoneTransform((HumanBodyBones)j); Transform targetBoneTransform = targetBones[i].GetBoneTransform((HumanBodyBones)j); if (sourceBoneTransform != null && targetBoneTransform != null) { boneRotationDifferences[i, j] = Quaternion.Inverse(sourceBoneTransform.rotation) * targetBoneTransform.rotation; } } } } private void CacheAllBoneTransforms() { // 소스 본 캐싱 cachedSourceBones = new Transform[55]; for (int i = 0; i < 55; i++) { cachedSourceBones[i] = sourceBone.GetBoneTransform((HumanBodyBones)i); } // 타겟 본 캐싱 cachedTargetBones = new Transform[targetBones.Length, 55]; for (int t = 0; t < targetBones.Length; t++) { for (int i = 0; i < 55; i++) { cachedTargetBones[t, i] = targetBones[t].GetBoneTransform((HumanBodyBones)i); } } } private void LateUpdate() { TransferPoses(); } private void TransferPoses() { if (sourceBone == null) { return; } for (int i = 0; i < targetBones.Length; i++) { if (targetBones[i] != null && targetBones[i].gameObject.activeInHierarchy) { TransferPoseToTarget(i); } } } private void TransferPoseToTarget(int targetIndex) { Animator targetBone = targetBones[targetIndex]; // 루트 회전 동기화 targetBone.transform.rotation = sourceBone.transform.rotation; // 모든 본에 대해 포즈 전송 for (int i = 0; i < 55; i++) { Transform targetBoneTransform = cachedTargetBones[targetIndex, i]; Transform sourceBoneTransform = cachedSourceBones[i]; if (targetBoneTransform != null && sourceBoneTransform != null) { // 회전 적용 targetBoneTransform.rotation = sourceBoneTransform.rotation * boneRotationDifferences[targetIndex, i]; // 펠비스 위치 동기화 (HumanBodyBones.Hips = 0) if (i == 0) { targetBoneTransform.position = sourceBoneTransform.position; } } } } }