Fix : 손가락 데이터 녹화가 안되는 부분 수정
This commit is contained in:
parent
caa8ab8dbd
commit
57ff5e65a7
@ -12,11 +12,11 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
#endif
|
#endif
|
||||||
using EasyMotionRecorder;
|
using EasyMotionRecorder;
|
||||||
using KindRetargeting;
|
|
||||||
using UniHumanoid;
|
using UniHumanoid;
|
||||||
|
|
||||||
namespace Entum
|
namespace Entum
|
||||||
@ -100,7 +100,26 @@ namespace Entum
|
|||||||
// SessionID 생성 (인스턴스 ID 제외)
|
// SessionID 생성 (인스턴스 ID 제외)
|
||||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
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에서 호출)
|
// 내부 메서드들 (SavePathManager에서 호출)
|
||||||
@ -147,22 +166,29 @@ namespace Entum
|
|||||||
{
|
{
|
||||||
return;
|
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
|
else
|
||||||
{
|
{
|
||||||
if (Time.frameCount % Application.targetFrameRate == 0)
|
if (Time.frameCount % Application.targetFrameRate == 0)
|
||||||
{
|
{
|
||||||
print("Motion_FPS=" + 1 / Time.deltaTime);
|
print("Motion_FPS=" + (1 / Time.deltaTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//現在のフレームのHumanoidの姿勢を取得
|
//現在のフレームのHumanoidの姿勢を取得
|
||||||
|
if (_poseHandler == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("PoseHandler가 초기화되지 않았습니다. 녹화를 중단합니다.");
|
||||||
|
RecordEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_poseHandler.GetHumanPose(ref _currentPose);
|
_poseHandler.GetHumanPose(ref _currentPose);
|
||||||
//posesに取得した姿勢を書き込む
|
//posesに取得한姿勢를書き込む
|
||||||
var serializedPose = new HumanoidPoses.SerializeHumanoidPose();
|
var serializedPose = new HumanoidPoses.SerializeHumanoidPose();
|
||||||
|
|
||||||
switch (_rootBoneSystem)
|
switch (_rootBoneSystem)
|
||||||
@ -173,17 +199,51 @@ namespace Entum
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionDataSettings.Rootbonesystem.Hipbone:
|
case MotionDataSettings.Rootbonesystem.Hipbone:
|
||||||
serializedPose.BodyRootPosition = _animator.GetBoneTransform(_targetRootBone).position;
|
var hipBone = _animator.GetBoneTransform(_targetRootBone);
|
||||||
serializedPose.BodyRootRotation = _animator.GetBoneTransform(_targetRootBone).rotation;
|
if (hipBone != null)
|
||||||
Debug.LogWarning(_animator.GetBoneTransform(_targetRootBone).position);
|
{
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var bodyTQ = new TQ(_currentPose.bodyPosition, _currentPose.bodyRotation);
|
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.BodyPosition = bodyTQ.t;
|
||||||
serializedPose.BodyRotation = bodyTQ.q;
|
serializedPose.BodyRotation = bodyTQ.q;
|
||||||
@ -214,6 +274,13 @@ namespace Entum
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PoseHandler 유효성 검사
|
||||||
|
if (_poseHandler == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("HumanPoseHandler가 초기화되지 않았습니다. 녹화를 시작할 수 없습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 세션 ID 생성 (인스턴스 ID 제외)
|
// 세션 ID 생성 (인스턴스 ID 제외)
|
||||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
||||||
|
|
||||||
@ -223,12 +290,27 @@ namespace Entum
|
|||||||
Poses.SessionID = SessionID;
|
Poses.SessionID = SessionID;
|
||||||
Poses.InstanceID = instanceID; // 인스턴스 ID 설정
|
Poses.InstanceID = instanceID; // 인스턴스 ID 설정
|
||||||
|
|
||||||
|
// T포즈 별도 저장 옵션이 활성화된 경우
|
||||||
|
if (_recordTPoseAtStart)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RecordTPoseAsFirstFrame();
|
||||||
|
Debug.Log("T포즈 데이터가 성공적으로 기록되었습니다.");
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"T포즈 녹화 중 오류 발생: {e.Message}");
|
||||||
|
// T포즈 실패해도 일반 녹화는 계속 진행
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RecordedTime = 0f;
|
RecordedTime = 0f;
|
||||||
StartTime = Time.time;
|
StartTime = Time.time;
|
||||||
FrameIndex = 0;
|
FrameIndex = 0;
|
||||||
_recording = true;
|
_recording = true;
|
||||||
|
|
||||||
Debug.Log($"모션 녹화 시작 - 인스턴스: {instanceID}, 세션: {SessionID}");
|
Debug.Log($"모션 녹화 시작 - 인스턴스: {instanceID}, 세션: {SessionID}, T포즈 옵션: {_recordTPoseAtStart}");
|
||||||
|
|
||||||
OnRecordStart?.Invoke();
|
OnRecordStart?.Invoke();
|
||||||
}
|
}
|
||||||
@ -242,32 +324,75 @@ namespace Entum
|
|||||||
|
|
||||||
private void SetTPose(Animator animator)
|
private void SetTPose(Animator animator)
|
||||||
{
|
{
|
||||||
// T-포즈 설정을 위한 임시 애니메이션 클립 생성
|
if (animator == null || animator.avatar == null)
|
||||||
var tPoseClip = new AnimationClip();
|
|
||||||
tPoseClip.name = "TPose";
|
|
||||||
|
|
||||||
// 모든 본을 T-포즈로 설정
|
|
||||||
var humanBones = animator.avatar.humanDescription.human;
|
|
||||||
foreach (var bone in humanBones)
|
|
||||||
{
|
{
|
||||||
// HumanBodyBones enum으로 변환
|
Debug.LogWarning("Animator 또는 Avatar가 null입니다. T포즈 설정을 건너뜁니다.");
|
||||||
HumanBodyBones bodyBone;
|
return;
|
||||||
if (System.Enum.TryParse(bone.humanName, out bodyBone))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
animator.Play("TPose");
|
try
|
||||||
|
{
|
||||||
|
// HumanPoseClip에서 T-포즈 데이터 로드 시도
|
||||||
|
var humanPoseClip = Resources.Load<UniHumanoid.HumanPoseClip>("T-Pose.pose");
|
||||||
|
if (humanPoseClip != null)
|
||||||
|
{
|
||||||
|
// 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포즈 설정을 수행합니다.");
|
||||||
|
|
||||||
|
// 기본 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()
|
private void RecordTPoseData()
|
||||||
@ -314,6 +439,7 @@ namespace Entum
|
|||||||
{
|
{
|
||||||
pose.HumanoidBones = new List<HumanoidPoses.SerializeHumanoidPose.HumanoidBone>();
|
pose.HumanoidBones = new List<HumanoidPoses.SerializeHumanoidPose.HumanoidBone>();
|
||||||
|
|
||||||
|
// 기존 avatar.humanDescription.human 본들 처리
|
||||||
var humanBones = animator.avatar.humanDescription.human;
|
var humanBones = animator.avatar.humanDescription.human;
|
||||||
foreach (var bone in humanBones)
|
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)
|
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;
|
return clip;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -713,6 +898,30 @@ namespace Entum
|
|||||||
return avatarIKGoal == AvatarIKGoal.LeftFoot ? HumanBodyBones.LeftFoot : HumanBodyBones.RightFoot;
|
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