Fix : 손가락 데이터 녹화가 안되는 부분 수정
This commit is contained in:
parent
caa8ab8dbd
commit
57ff5e65a7
@ -12,11 +12,11 @@ using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using EasyMotionRecorder;
|
||||
using KindRetargeting;
|
||||
using UniHumanoid;
|
||||
|
||||
namespace Entum
|
||||
@ -100,7 +100,26 @@ namespace Entum
|
||||
// SessionID 생성 (인스턴스 ID 제외)
|
||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
||||
|
||||
_poseHandler = new HumanPoseHandler(_animator.avatar, _animator.transform);
|
||||
// HumanPoseHandler 안전한 초기화
|
||||
if (_animator.avatar != null && _animator.isHuman)
|
||||
{
|
||||
try
|
||||
{
|
||||
_poseHandler = new HumanPoseHandler(_animator.avatar, _animator.transform);
|
||||
Debug.Log($"HumanPoseHandler 초기화 완료 - 아바타: {_animator.avatar.name}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"HumanPoseHandler 초기화 실패: {e.Message}");
|
||||
_poseHandler = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"아바타가 휴머노이드가 아니거나 Avatar가 설정되지 않았습니다. " +
|
||||
$"Avatar: {_animator.avatar}, IsHuman: {_animator.isHuman}");
|
||||
_poseHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 내부 메서드들 (SavePathManager에서 호출)
|
||||
@ -147,22 +166,29 @@ namespace Entum
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (FrameIndex % TargetFPS == 0)
|
||||
if (FrameIndex % TargetFPS == 0 && FrameIndex > 0 && RecordedTime > 0)
|
||||
{
|
||||
print("Motion_FPS=" + 1 / (RecordedTime / FrameIndex));
|
||||
print("Motion_FPS=" + (FrameIndex / RecordedTime));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Time.frameCount % Application.targetFrameRate == 0)
|
||||
{
|
||||
print("Motion_FPS=" + 1 / Time.deltaTime);
|
||||
print("Motion_FPS=" + (1 / Time.deltaTime));
|
||||
}
|
||||
}
|
||||
|
||||
//現在のフレームのHumanoidの姿勢を取得
|
||||
if (_poseHandler == null)
|
||||
{
|
||||
Debug.LogError("PoseHandler가 초기화되지 않았습니다. 녹화를 중단합니다.");
|
||||
RecordEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
_poseHandler.GetHumanPose(ref _currentPose);
|
||||
//posesに取得した姿勢を書き込む
|
||||
//posesに取得한姿勢를書き込む
|
||||
var serializedPose = new HumanoidPoses.SerializeHumanoidPose();
|
||||
|
||||
switch (_rootBoneSystem)
|
||||
@ -173,17 +199,51 @@ namespace Entum
|
||||
break;
|
||||
|
||||
case MotionDataSettings.Rootbonesystem.Hipbone:
|
||||
serializedPose.BodyRootPosition = _animator.GetBoneTransform(_targetRootBone).position;
|
||||
serializedPose.BodyRootRotation = _animator.GetBoneTransform(_targetRootBone).rotation;
|
||||
Debug.LogWarning(_animator.GetBoneTransform(_targetRootBone).position);
|
||||
var hipBone = _animator.GetBoneTransform(_targetRootBone);
|
||||
if (hipBone != null)
|
||||
{
|
||||
serializedPose.BodyRootPosition = hipBone.position;
|
||||
serializedPose.BodyRootRotation = hipBone.rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"타겟 루트 본 {_targetRootBone}을 찾을 수 없습니다. Object Root로 대체합니다.");
|
||||
serializedPose.BodyRootPosition = _animator.transform.localPosition;
|
||||
serializedPose.BodyRootRotation = _animator.transform.localRotation;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
var bodyTQ = new TQ(_currentPose.bodyPosition, _currentPose.bodyRotation);
|
||||
var LeftFootTQ = new TQ(_animator.GetBoneTransform(IK_LeftFootBone).position, _animator.GetBoneTransform(IK_LeftFootBone).rotation);
|
||||
var RightFootTQ = new TQ(_animator.GetBoneTransform(IK_RightFootBone).position, _animator.GetBoneTransform(IK_RightFootBone).rotation);
|
||||
|
||||
// 발 본 안전성 검사
|
||||
var leftFootBone = _animator.GetBoneTransform(IK_LeftFootBone);
|
||||
var rightFootBone = _animator.GetBoneTransform(IK_RightFootBone);
|
||||
|
||||
TQ LeftFootTQ, RightFootTQ;
|
||||
|
||||
if (leftFootBone != null)
|
||||
{
|
||||
LeftFootTQ = new TQ(leftFootBone.position, leftFootBone.rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"왼발 본 {IK_LeftFootBone}을 찾을 수 없습니다. 기본값을 사용합니다.");
|
||||
LeftFootTQ = new TQ(Vector3.zero, Quaternion.identity);
|
||||
}
|
||||
|
||||
if (rightFootBone != null)
|
||||
{
|
||||
RightFootTQ = new TQ(rightFootBone.position, rightFootBone.rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"오른발 본 {IK_RightFootBone}을 찾을 수 없습니다. 기본값을 사용합니다.");
|
||||
RightFootTQ = new TQ(Vector3.zero, Quaternion.identity);
|
||||
}
|
||||
|
||||
serializedPose.BodyPosition = bodyTQ.t;
|
||||
serializedPose.BodyRotation = bodyTQ.q;
|
||||
@ -214,6 +274,13 @@ namespace Entum
|
||||
return;
|
||||
}
|
||||
|
||||
// PoseHandler 유효성 검사
|
||||
if (_poseHandler == null)
|
||||
{
|
||||
Debug.LogError("HumanPoseHandler가 초기화되지 않았습니다. 녹화를 시작할 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 세션 ID 생성 (인스턴스 ID 제외)
|
||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
||||
|
||||
@ -223,12 +290,27 @@ namespace Entum
|
||||
Poses.SessionID = SessionID;
|
||||
Poses.InstanceID = instanceID; // 인스턴스 ID 설정
|
||||
|
||||
// T포즈 별도 저장 옵션이 활성화된 경우
|
||||
if (_recordTPoseAtStart)
|
||||
{
|
||||
try
|
||||
{
|
||||
RecordTPoseAsFirstFrame();
|
||||
Debug.Log("T포즈 데이터가 성공적으로 기록되었습니다.");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"T포즈 녹화 중 오류 발생: {e.Message}");
|
||||
// T포즈 실패해도 일반 녹화는 계속 진행
|
||||
}
|
||||
}
|
||||
|
||||
RecordedTime = 0f;
|
||||
StartTime = Time.time;
|
||||
FrameIndex = 0;
|
||||
_recording = true;
|
||||
|
||||
Debug.Log($"모션 녹화 시작 - 인스턴스: {instanceID}, 세션: {SessionID}");
|
||||
Debug.Log($"모션 녹화 시작 - 인스턴스: {instanceID}, 세션: {SessionID}, T포즈 옵션: {_recordTPoseAtStart}");
|
||||
|
||||
OnRecordStart?.Invoke();
|
||||
}
|
||||
@ -242,32 +324,75 @@ namespace Entum
|
||||
|
||||
private void SetTPose(Animator animator)
|
||||
{
|
||||
// T-포즈 설정을 위한 임시 애니메이션 클립 생성
|
||||
var tPoseClip = new AnimationClip();
|
||||
tPoseClip.name = "TPose";
|
||||
|
||||
// 모든 본을 T-포즈로 설정
|
||||
var humanBones = animator.avatar.humanDescription.human;
|
||||
foreach (var bone in humanBones)
|
||||
if (animator == null || animator.avatar == null)
|
||||
{
|
||||
// HumanBodyBones enum으로 변환
|
||||
HumanBodyBones bodyBone;
|
||||
if (System.Enum.TryParse(bone.humanName, out bodyBone))
|
||||
Debug.LogWarning("Animator 또는 Avatar가 null입니다. T포즈 설정을 건너뜁니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// HumanPoseClip에서 T-포즈 데이터 로드 시도
|
||||
var humanPoseClip = Resources.Load<UniHumanoid.HumanPoseClip>("T-Pose.pose");
|
||||
if (humanPoseClip != null)
|
||||
{
|
||||
var boneTransform = animator.GetBoneTransform(bodyBone);
|
||||
if (boneTransform != null)
|
||||
{
|
||||
var curve = new AnimationCurve();
|
||||
curve.AddKey(0, 0);
|
||||
tPoseClip.SetCurve(boneTransform.name, typeof(Transform), "localRotation.x", curve);
|
||||
tPoseClip.SetCurve(boneTransform.name, typeof(Transform), "localRotation.y", curve);
|
||||
tPoseClip.SetCurve(boneTransform.name, typeof(Transform), "localRotation.z", curve);
|
||||
tPoseClip.SetCurve(boneTransform.name, typeof(Transform), "localRotation.w", curve);
|
||||
}
|
||||
// T포즈 데이터를 적용
|
||||
var pose = humanPoseClip.GetPose();
|
||||
SetPoseToAnimator(animator.avatar, animator.transform, pose);
|
||||
|
||||
Debug.Log("T-포즈가 HumanPoseClip에서 성공적으로 로드되었습니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// HumanPoseClip이 없는 경우 기본 T포즈 설정
|
||||
Debug.LogWarning("T-Pose.pose 리소스를 찾을 수 없습니다. 기본 T포즈를 설정합니다.");
|
||||
SetDefaultTPose(animator);
|
||||
}
|
||||
|
||||
// UpperChest 본 위치 초기화 (카인드리타겟팅과 동일)
|
||||
Transform upperChest = animator.GetBoneTransform(HumanBodyBones.UpperChest);
|
||||
if (upperChest != null)
|
||||
{
|
||||
upperChest.localPosition = Vector3.zero;
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"T포즈 설정 중 오류 발생: {e.Message}");
|
||||
SetDefaultTPose(animator);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HumanPose를 Animator에 적용하는 내부 메서드
|
||||
/// </summary>
|
||||
private void SetPoseToAnimator(Avatar avatar, Transform transform, HumanPose pose)
|
||||
{
|
||||
var handler = new HumanPoseHandler(avatar, transform);
|
||||
handler.SetHumanPose(ref pose);
|
||||
handler.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 기본 T포즈 설정 (HumanPoseClip이 없는 경우 백업용)
|
||||
/// </summary>
|
||||
private void SetDefaultTPose(Animator animator)
|
||||
{
|
||||
Debug.Log("기본 T포즈 설정을 수행합니다.");
|
||||
|
||||
animator.Play("TPose");
|
||||
// 기본 T포즈 생성 - Muscles를 0으로 설정
|
||||
var defaultTPose = new HumanPose();
|
||||
defaultTPose.bodyPosition = Vector3.zero;
|
||||
defaultTPose.bodyRotation = Quaternion.identity;
|
||||
|
||||
// 모든 머슬을 0으로 설정 (T포즈)
|
||||
defaultTPose.muscles = new float[HumanTrait.MuscleCount];
|
||||
for (int i = 0; i < HumanTrait.MuscleCount; i++)
|
||||
{
|
||||
defaultTPose.muscles[i] = 0f;
|
||||
}
|
||||
|
||||
SetPoseToAnimator(animator.avatar, animator.transform, defaultTPose);
|
||||
}
|
||||
|
||||
private void RecordTPoseData()
|
||||
@ -314,6 +439,7 @@ namespace Entum
|
||||
{
|
||||
pose.HumanoidBones = new List<HumanoidPoses.SerializeHumanoidPose.HumanoidBone>();
|
||||
|
||||
// 기존 avatar.humanDescription.human 본들 처리
|
||||
var humanBones = animator.avatar.humanDescription.human;
|
||||
foreach (var bone in humanBones)
|
||||
{
|
||||
@ -337,6 +463,59 @@ namespace Entum
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 손가락 본들 추가 처리 (누락된 것들을 위해)
|
||||
AddFingerBones(animator, ref pose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 손가락 본들을 추가로 처리하는 메서드
|
||||
/// </summary>
|
||||
private static void AddFingerBones(Animator animator, ref HumanoidPoses.SerializeHumanoidPose pose)
|
||||
{
|
||||
// 이미 추가된 본들의 이름을 저장
|
||||
var existingBoneNames = new HashSet<string>();
|
||||
foreach (var bone in pose.HumanoidBones)
|
||||
{
|
||||
existingBoneNames.Add(bone.Name);
|
||||
}
|
||||
|
||||
// 모든 손가락 본들을 정의
|
||||
var fingerBones = new HumanBodyBones[]
|
||||
{
|
||||
// 왼손 손가락들
|
||||
HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,
|
||||
HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,
|
||||
HumanBodyBones.LeftMiddleProximal, HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,
|
||||
HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,
|
||||
HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,
|
||||
|
||||
// 오른손 손가락들
|
||||
HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,
|
||||
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)
|
||||
{
|
||||
var boneTransform = animator.GetBoneTransform(fingerBone);
|
||||
if (boneTransform != null)
|
||||
{
|
||||
var humanoidBone = new HumanoidPoses.SerializeHumanoidPose.HumanoidBone();
|
||||
humanoidBone.Set(animator.transform, boneTransform);
|
||||
|
||||
// 중복 확인 (이미 추가되지 않은 경우만 추가)
|
||||
if (!existingBoneNames.Contains(humanoidBone.Name))
|
||||
{
|
||||
pose.HumanoidBones.Add(humanoidBone);
|
||||
existingBoneNames.Add(humanoidBone.Name);
|
||||
//Debug.Log($"손가락 본 추가: {fingerBone} -> {humanoidBone.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsElbowBone(Transform bone)
|
||||
@ -654,6 +833,12 @@ namespace Entum
|
||||
}
|
||||
}
|
||||
|
||||
// 손가락 본들이 포함되었는지 로깅
|
||||
var fingerBoneCount = boneCurves.Keys.Count(name =>
|
||||
name.Contains("Thumb") || name.Contains("Index") || name.Contains("Middle") ||
|
||||
name.Contains("Ring") || name.Contains("Little") || name.Contains("Pinky"));
|
||||
Debug.Log($"제네릭 애니메이션 클립 생성 완료 - 총 {boneCurves.Count}개 본, 손가락 본 {fingerBoneCount}개 포함");
|
||||
|
||||
return clip;
|
||||
}
|
||||
#endif
|
||||
@ -713,6 +898,30 @@ namespace Entum
|
||||
return avatarIKGoal == AvatarIKGoal.LeftFoot ? HumanBodyBones.LeftFoot : HumanBodyBones.RightFoot;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 컴포넌트가 파괴될 때 리소스를 정리합니다.
|
||||
/// </summary>
|
||||
private void OnDestroy()
|
||||
{
|
||||
// HumanPoseHandler 안전하게 정리
|
||||
if (_poseHandler != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_poseHandler.Dispose();
|
||||
Debug.Log("HumanPoseHandler가 정리되었습니다.");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"HumanPoseHandler 정리 중 오류 발생: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_poseHandler = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user