Add : 모션 녹화 시스템 업데이트 패치
This commit is contained in:
parent
da526dc72b
commit
c73c7cbc18
@ -267,7 +267,7 @@ namespace Entum
|
|||||||
FrameIndex++;
|
FrameIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecordStart()
|
public void RecordStart()
|
||||||
{
|
{
|
||||||
if (_recording)
|
if (_recording)
|
||||||
{
|
{
|
||||||
@ -421,7 +421,7 @@ namespace Entum
|
|||||||
Debug.Log("T-포즈 데이터가 저장되었습니다.");
|
Debug.Log("T-포즈 데이터가 저장되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecordEnd()
|
public void RecordEnd()
|
||||||
{
|
{
|
||||||
if (!_recording)
|
if (!_recording)
|
||||||
{
|
{
|
||||||
|
|||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/BaseAvatar - OptiTrack ver 2.prefab
(Stored with Git LFS)
vendored
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/BaseAvatar - OptiTrack ver 2.prefab
(Stored with Git LFS)
vendored
Binary file not shown.
8
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data.meta
vendored
Normal file
8
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6f705ffb70fa1a140bf73185aef44529
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4b1499ea416adce4daaed7b0b3b2b001
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.Avatar/VrmAvatar.asset
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.Avatar/VrmAvatar.asset
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3c4b192ca3a426b48819a1106d1d927b
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 9000000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9a46274a4e01e9d45bc0a3f2c25d5d02
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.Materials/newton.asset
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.Materials/newton.asset
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f5c6e42d92f8225488a96dfaf88b9051
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d1094b1299f0ba44b9f618231c354db5
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.Meshes/newton.baked.asset
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.Meshes/newton.baked.asset
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 23aa04f3a9d0bb84bba05888737ec16e
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 4300000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.prefab
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/BaseAvatar ver 2/Hand Data/Hand Data.prefab
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e40a686a525bda34ebf267268d8b2616
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/BaseAvatar - OptiTrack Last.prefab
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/BaseAvatar - OptiTrack Last.prefab
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c470e4106f9329048b690874ec8ef603
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Client - OptiTrack.prefab
(Stored with Git LFS)
vendored
BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Client - OptiTrack.prefab
(Stored with Git LFS)
vendored
Binary file not shown.
@ -21,7 +21,7 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
|
|
||||||
[Tooltip("Motive의 스켈레톤 에셋 이름")]
|
[Tooltip("Motive의 스켈레톤 에셋 이름")]
|
||||||
public string SkeletonAssetName = "Skeleton1";
|
public string SkeletonAssetName = "Skeleton1";
|
||||||
private Animator TargetAnimator;
|
public Animator TargetAnimator;
|
||||||
|
|
||||||
[Header("모션 적용 범위")]
|
[Header("모션 적용 범위")]
|
||||||
[Tooltip("모션 캡처 데이터를 적용할 범위 선택")]
|
[Tooltip("모션 캡처 데이터를 적용할 범위 선택")]
|
||||||
@ -37,18 +37,8 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
|
|
||||||
private float updateInterval = 0.1f;
|
private float updateInterval = 0.1f;
|
||||||
|
|
||||||
// Actor 컴포넌트 참조 (Rokoko Actor와 동기화용)
|
|
||||||
private Rokoko.Inputs.Actor m_actor;
|
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
TargetAnimator = GetComponent<Animator>();
|
|
||||||
if (TargetAnimator == null)
|
|
||||||
{
|
|
||||||
//Debug.LogError("이 게임오브젝트에서 Animator 컴포넌트를 찾을 수 없습니다.", this);
|
|
||||||
enabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeStreamingClient();
|
InitializeStreamingClient();
|
||||||
|
|
||||||
@ -61,9 +51,6 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
|
|
||||||
InitializeBoneMapping();
|
InitializeBoneMapping();
|
||||||
|
|
||||||
// Actor 컴포넌트 찾기 및 프로파일 이름 동기화
|
|
||||||
SyncActorProfileName();
|
|
||||||
|
|
||||||
// 주기적으로 스켈레톤 연결 상태를 확인하는 코루틴 시작
|
// 주기적으로 스켈레톤 연결 상태를 확인하는 코루틴 시작
|
||||||
StartCoroutine(CheckSkeletonConnectionPeriodically());
|
StartCoroutine(CheckSkeletonConnectionPeriodically());
|
||||||
}
|
}
|
||||||
@ -136,8 +123,12 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (skelState.BonePoses.TryGetValue(bone.Id, out OptitrackPose bonePose))
|
if (skelState.BonePoses.TryGetValue(bone.Id, out OptitrackPose bonePose))
|
||||||
{
|
{
|
||||||
// 위치는 항상 업데이트 (Hip 등 루트 본의 경우)
|
// 손가락의 경우 로컬 포지션 데이터를 받지 않음
|
||||||
boneTransform.localPosition = bonePose.Position;
|
if (!IsFingerBone(optitrackBoneName))
|
||||||
|
{
|
||||||
|
// 위치는 항상 업데이트 (Hip 등 루트 본의 경우)
|
||||||
|
boneTransform.localPosition = bonePose.Position;
|
||||||
|
}
|
||||||
|
|
||||||
// 회전 업데이트
|
// 회전 업데이트
|
||||||
boneTransform.localRotation = bonePose.Orientation;
|
boneTransform.localRotation = bonePose.Orientation;
|
||||||
@ -178,27 +169,6 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
// 스켈레톤 에셋 이름을 제외한 기본 매핑 설정
|
// 스켈레톤 에셋 이름을 제외한 기본 매핑 설정
|
||||||
SetupBoneNameMapping();
|
SetupBoneNameMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Actor 컴포넌트의 프로파일 이름을 OptiTrack 스켈레톤 이름과 동기화
|
|
||||||
/// </summary>
|
|
||||||
private void SyncActorProfileName()
|
|
||||||
{
|
|
||||||
// 같은 게임오브젝트에서 Actor 컴포넌트 찾기
|
|
||||||
m_actor = GetComponent<Rokoko.Inputs.Actor>();
|
|
||||||
|
|
||||||
if (m_actor != null)
|
|
||||||
{
|
|
||||||
// Actor의 프로파일 이름을 OptiTrack 스켈레톤 이름으로 설정
|
|
||||||
m_actor.profileName = this.SkeletonAssetName;
|
|
||||||
Debug.Log($"[OptiTrack] Actor 프로파일 이름을 '{SkeletonAssetName}'으로 동기화했습니다.", this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogWarning("[OptiTrack] 같은 게임오브젝트에서 Actor 컴포넌트를 찾을 수 없습니다.", this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupBoneNameMapping()
|
private void SetupBoneNameMapping()
|
||||||
{
|
{
|
||||||
// 기본 본 매핑 (스켈레톤 에셋 이름 없이)
|
// 기본 본 매핑 (스켈레톤 에셋 이름 없이)
|
||||||
|
|||||||
BIN
Assets/Prefeb/이벤트 컨트롤러 - 녹화 세팅.prefab
(Stored with Git LFS)
BIN
Assets/Prefeb/이벤트 컨트롤러 - 녹화 세팅.prefab
(Stored with Git LFS)
Binary file not shown.
8
Assets/ResourcesData/Project/250821_모션촬영/모션.meta
Normal file
8
Assets/ResourcesData/Project/250821_모션촬영/모션.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e0123bef6b5bef14abc800ff6ed2ded4
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/ResourcesData/Project/250822_모션촬영/250822_모션촬영.unity
(Stored with Git LFS)
BIN
Assets/ResourcesData/Project/250822_모션촬영/250822_모션촬영.unity
(Stored with Git LFS)
Binary file not shown.
192
Assets/Scripts/KindRetargeting/OffsetTransfer.cs
Normal file
192
Assets/Scripts/KindRetargeting/OffsetTransfer.cs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace KindRetargeting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 아바타 간의 회전 오프셋을 계산하고 포즈 데이터를 복사하는 기능을 제공합니다.
|
||||||
|
/// </summary>
|
||||||
|
public class OffsetTransfer : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("아바타 설정")]
|
||||||
|
[SerializeField] public Animator sourceAnimator; // 원본 아바타의 Animator
|
||||||
|
[SerializeField] public Animator targetAnimator; // 대상 아바타의 Animator
|
||||||
|
|
||||||
|
[Header("오프셋 설정")]
|
||||||
|
[SerializeField] private bool autoCalculateOnStart = true; // 시작 시 자동 계산 여부
|
||||||
|
[SerializeField] private bool autoCopyPose = true; // 매 프레임마다 자동으로 포즈 복사 여부
|
||||||
|
|
||||||
|
// 본별 회전 오프셋을 저장하는 딕셔너리
|
||||||
|
private Dictionary<HumanBodyBones, Quaternion> rotationOffsets = new Dictionary<HumanBodyBones, Quaternion>();
|
||||||
|
|
||||||
|
#region 프로퍼티
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 계산된 회전 오프셋 딕셔너리를 반환합니다.
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<HumanBodyBones, Quaternion> RotationOffsets => rotationOffsets;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 초기화
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
if (autoCalculateOnStart)
|
||||||
|
{
|
||||||
|
CalculateRotationOffsets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 업데이트
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (autoCopyPose)
|
||||||
|
{
|
||||||
|
CopyPoseToTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LateUpdate()
|
||||||
|
{
|
||||||
|
if (autoCopyPose)
|
||||||
|
{
|
||||||
|
CopyPoseToTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 오프셋 계산
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 원본과 대상 아바타의 각 본 간 회전 오프셋을 계산하여 저장합니다.
|
||||||
|
/// </summary>
|
||||||
|
public void CalculateRotationOffsets()
|
||||||
|
{
|
||||||
|
if (sourceAnimator == null || targetAnimator == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("소스 또는 타겟 Animator가 설정되지 않았습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dictionary가 null이면 초기화
|
||||||
|
if (rotationOffsets == null)
|
||||||
|
{
|
||||||
|
rotationOffsets = new Dictionary<HumanBodyBones, Quaternion>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모든 본에 대해 오프셋 계산 (기본 몸체 본 + 손가락 본 + UpperChest)
|
||||||
|
for (int i = 0; i <= 54; i++)
|
||||||
|
{
|
||||||
|
HumanBodyBones bone = (HumanBodyBones)i;
|
||||||
|
Transform sourceBone = sourceAnimator.GetBoneTransform(bone);
|
||||||
|
Transform targetBone = targetAnimator.GetBoneTransform(bone);
|
||||||
|
|
||||||
|
if (sourceBone != null && targetBone != null)
|
||||||
|
{
|
||||||
|
Quaternion offset = Quaternion.Inverse(sourceBone.rotation) * targetBone.rotation;
|
||||||
|
|
||||||
|
if (rotationOffsets.ContainsKey(bone))
|
||||||
|
{
|
||||||
|
rotationOffsets[bone] = offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rotationOffsets.Add(bone, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"회전 오프셋 계산 완료: {rotationOffsets.Count}개 본");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 특정 본의 회전 오프셋을 반환합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bone">본 타입</param>
|
||||||
|
/// <returns>회전 오프셋 (없으면 Identity)</returns>
|
||||||
|
public Quaternion GetRotationOffset(HumanBodyBones bone)
|
||||||
|
{
|
||||||
|
if (rotationOffsets.ContainsKey(bone))
|
||||||
|
{
|
||||||
|
return rotationOffsets[bone];
|
||||||
|
}
|
||||||
|
return Quaternion.identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 특정 본에 회전 오프셋을 적용합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bone">본 타입</param>
|
||||||
|
/// <param name="originalRotation">원본 회전값</param>
|
||||||
|
/// <returns>오프셋이 적용된 회전값</returns>
|
||||||
|
public Quaternion ApplyRotationOffset(HumanBodyBones bone, Quaternion originalRotation)
|
||||||
|
{
|
||||||
|
if (rotationOffsets.ContainsKey(bone))
|
||||||
|
{
|
||||||
|
return originalRotation * rotationOffsets[bone];
|
||||||
|
}
|
||||||
|
return originalRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 포즈 복사
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 원본 아바타의 포즈를 대상 아바타에 복사합니다.
|
||||||
|
/// </summary>
|
||||||
|
public void CopyPoseToTarget()
|
||||||
|
{
|
||||||
|
if (sourceAnimator == null || targetAnimator == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("소스 또는 타겟 Animator가 설정되지 않았습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모든 본에 대해 포즈 복사
|
||||||
|
for (int i = 0; i <= 54; i++)
|
||||||
|
{
|
||||||
|
HumanBodyBones bone = (HumanBodyBones)i;
|
||||||
|
Transform sourceBone = sourceAnimator.GetBoneTransform(bone);
|
||||||
|
Transform targetBone = targetAnimator.GetBoneTransform(bone);
|
||||||
|
|
||||||
|
if (sourceBone != null && targetBone != null)
|
||||||
|
{
|
||||||
|
// 회전은 오프셋 적용, 위치는 그대로 복사
|
||||||
|
Quaternion targetRotation = ApplyRotationOffset(bone, sourceBone.rotation);
|
||||||
|
targetBone.rotation = targetRotation;
|
||||||
|
targetBone.position = sourceBone.position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 특정 본의 포즈를 복사합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bone">복사할 본</param>
|
||||||
|
public void CopyBonePose(HumanBodyBones bone)
|
||||||
|
{
|
||||||
|
if (sourceAnimator == null || targetAnimator == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("소스 또는 타겟 Animator가 설정되지 않았습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform sourceBone = sourceAnimator.GetBoneTransform(bone);
|
||||||
|
Transform targetBone = targetAnimator.GetBoneTransform(bone);
|
||||||
|
|
||||||
|
if (sourceBone != null && targetBone != null)
|
||||||
|
{
|
||||||
|
Quaternion targetRotation = ApplyRotationOffset(bone, sourceBone.rotation);
|
||||||
|
targetBone.rotation = targetRotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/Scripts/KindRetargeting/OffsetTransfer.cs.meta
Normal file
2
Assets/Scripts/KindRetargeting/OffsetTransfer.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2252970a315b77e4eacbd7dcfb654842
|
||||||
Loading…
x
Reference in New Issue
Block a user