Add : 모션 녹화 시스템 업데이트 패치
This commit is contained in:
parent
da526dc72b
commit
c73c7cbc18
@ -267,7 +267,7 @@ namespace Entum
|
||||
FrameIndex++;
|
||||
}
|
||||
|
||||
private void RecordStart()
|
||||
public void RecordStart()
|
||||
{
|
||||
if (_recording)
|
||||
{
|
||||
@ -421,7 +421,7 @@ namespace Entum
|
||||
Debug.Log("T-포즈 데이터가 저장되었습니다.");
|
||||
}
|
||||
|
||||
private void RecordEnd()
|
||||
public void RecordEnd()
|
||||
{
|
||||
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의 스켈레톤 에셋 이름")]
|
||||
public string SkeletonAssetName = "Skeleton1";
|
||||
private Animator TargetAnimator;
|
||||
public Animator TargetAnimator;
|
||||
|
||||
[Header("모션 적용 범위")]
|
||||
[Tooltip("모션 캡처 데이터를 적용할 범위 선택")]
|
||||
@ -37,18 +37,8 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
||||
|
||||
private float updateInterval = 0.1f;
|
||||
|
||||
// Actor 컴포넌트 참조 (Rokoko Actor와 동기화용)
|
||||
private Rokoko.Inputs.Actor m_actor;
|
||||
|
||||
void Start()
|
||||
{
|
||||
TargetAnimator = GetComponent<Animator>();
|
||||
if (TargetAnimator == null)
|
||||
{
|
||||
//Debug.LogError("이 게임오브젝트에서 Animator 컴포넌트를 찾을 수 없습니다.", this);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeStreamingClient();
|
||||
|
||||
@ -61,9 +51,6 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
||||
|
||||
InitializeBoneMapping();
|
||||
|
||||
// Actor 컴포넌트 찾기 및 프로파일 이름 동기화
|
||||
SyncActorProfileName();
|
||||
|
||||
// 주기적으로 스켈레톤 연결 상태를 확인하는 코루틴 시작
|
||||
StartCoroutine(CheckSkeletonConnectionPeriodically());
|
||||
}
|
||||
@ -136,8 +123,12 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
||||
{
|
||||
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;
|
||||
@ -178,27 +169,6 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
||||
// 스켈레톤 에셋 이름을 제외한 기본 매핑 설정
|
||||
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()
|
||||
{
|
||||
// 기본 본 매핑 (스켈레톤 에셋 이름 없이)
|
||||
|
||||
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