219 lines
6.6 KiB
C#
219 lines
6.6 KiB
C#
/**
|
|
[EasyMotionRecorder]
|
|
|
|
Copyright (c) 2018 Duo.inc
|
|
|
|
This software is released under the MIT License.
|
|
http://opensource.org/licenses/mit-license.php
|
|
*/
|
|
|
|
using UnityEngine;
|
|
using System;
|
|
|
|
namespace Entum
|
|
{
|
|
/// <summary>
|
|
/// 모션 데이터 재생 클래스
|
|
/// SpringBone, DynamicBone, BulletPhysicsImpl 등의 흔들리는 에셋의 Script Execution Order를 20000 등
|
|
/// 큰 값으로 설정해주세요.
|
|
/// DefaultExecutionOrder(11000)은 VRIK계보다 처리 순서를 느리게 한다는 의도입니다
|
|
/// </summary>
|
|
[DefaultExecutionOrder(11000)]
|
|
public class MotionDataPlayer : MonoBehaviour
|
|
{
|
|
[SerializeField]
|
|
private KeyCode _playStartKey = KeyCode.S;
|
|
[SerializeField]
|
|
private KeyCode _playStopKey = KeyCode.T;
|
|
|
|
[SerializeField]
|
|
protected HumanoidPoses RecordedMotionData;
|
|
[SerializeField]
|
|
private Animator _animator;
|
|
|
|
[SerializeField, Tooltip("재생 시작 프레임을 지정합니다. 0이면 파일 시작부터 시작합니다")]
|
|
private int _startFrame;
|
|
[SerializeField]
|
|
private bool _playing;
|
|
[SerializeField]
|
|
private int _frameIndex;
|
|
|
|
[SerializeField, Tooltip("普段はOBJECTROOTで問題ないです。特殊な機材の場合は変更してください")]
|
|
private MotionDataSettings.Rootbonesystem _rootBoneSystem = MotionDataSettings.Rootbonesystem.Objectroot;
|
|
[SerializeField, Tooltip("rootBoneSystemがOBJECTROOTの時は使われないパラメータです。")]
|
|
private HumanBodyBones _targetRootBone = HumanBodyBones.Hips;
|
|
|
|
[HideInInspector, SerializeField] private string instanceID = "";
|
|
[HideInInspector, SerializeField] private bool useDontDestroyOnLoad = false;
|
|
|
|
private HumanPoseHandler _poseHandler;
|
|
private Action _onPlayFinish;
|
|
private float _playingTime;
|
|
|
|
private void Awake()
|
|
{
|
|
if (_animator == null)
|
|
{
|
|
Debug.LogError("MotionDataPlayerにanimatorがセットされていません。MotionDataPlayerを削除します。");
|
|
Destroy(this);
|
|
return;
|
|
}
|
|
|
|
// 인스턴스 ID가 비어있으면 자동 생성
|
|
if (string.IsNullOrEmpty(instanceID))
|
|
{
|
|
instanceID = System.Guid.NewGuid().ToString().Substring(0, 8);
|
|
}
|
|
|
|
// DontDestroyOnLoad 설정 (선택적)
|
|
if (useDontDestroyOnLoad)
|
|
{
|
|
DontDestroyOnLoad(gameObject);
|
|
}
|
|
|
|
_poseHandler = new HumanPoseHandler(_animator.avatar, _animator.transform);
|
|
_onPlayFinish += StopMotion;
|
|
}
|
|
|
|
// 매 프레임마다 호출
|
|
private void Update()
|
|
{
|
|
if (Input.GetKeyDown(_playStartKey))
|
|
{
|
|
PlayMotion();
|
|
}
|
|
|
|
if (Input.GetKeyDown(_playStopKey))
|
|
{
|
|
StopMotion();
|
|
}
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!_playing)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_playingTime += Time.deltaTime;
|
|
SetHumanPose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모션 데이터 재생 시작
|
|
/// </summary>
|
|
private void PlayMotion()
|
|
{
|
|
if (_playing)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (RecordedMotionData == null)
|
|
{
|
|
Debug.LogError("재생할 모션 데이터가 없습니다.");
|
|
return;
|
|
}
|
|
|
|
_playing = true;
|
|
_frameIndex = _startFrame;
|
|
_playingTime = 0f;
|
|
|
|
Debug.Log($"모션 재생 시작 - 인스턴스: {instanceID}, 시작 프레임: {_startFrame}");
|
|
}
|
|
|
|
private void StopMotion()
|
|
{
|
|
if (!_playing)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_playing = false;
|
|
Debug.Log($"모션 재생 중지 - 인스턴스: {instanceID}, 재생된 프레임: {_frameIndex}");
|
|
}
|
|
|
|
private void SetHumanPose()
|
|
{
|
|
if (RecordedMotionData == null || RecordedMotionData.Poses == null || RecordedMotionData.Poses.Count == 0)
|
|
{
|
|
StopMotion();
|
|
return;
|
|
}
|
|
|
|
if (_frameIndex >= RecordedMotionData.Poses.Count)
|
|
{
|
|
StopMotion();
|
|
_onPlayFinish?.Invoke();
|
|
return;
|
|
}
|
|
|
|
var pose = RecordedMotionData.Poses[_frameIndex];
|
|
var humanPose = new HumanPose();
|
|
|
|
// 본 데이터 설정
|
|
if (pose.HumanoidBones != null)
|
|
{
|
|
foreach (var bone in pose.HumanoidBones)
|
|
{
|
|
// HumanBodyBones enum으로 변환
|
|
HumanBodyBones bodyBone;
|
|
if (System.Enum.TryParse(bone.Name, out bodyBone))
|
|
{
|
|
var boneTransform = _animator.GetBoneTransform(bodyBone);
|
|
if (boneTransform != null)
|
|
{
|
|
boneTransform.localPosition = bone.LocalPosition;
|
|
boneTransform.localRotation = bone.LocalRotation;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 근육 데이터 설정
|
|
if (pose.Muscles != null && pose.Muscles.Length > 0)
|
|
{
|
|
humanPose.muscles = pose.Muscles;
|
|
}
|
|
|
|
// 루트 본 설정
|
|
switch (_rootBoneSystem)
|
|
{
|
|
case MotionDataSettings.Rootbonesystem.Objectroot:
|
|
_animator.transform.localPosition = pose.BodyRootPosition;
|
|
_animator.transform.localRotation = pose.BodyRootRotation;
|
|
break;
|
|
|
|
case MotionDataSettings.Rootbonesystem.Hipbone:
|
|
var hipBone = _animator.GetBoneTransform(_targetRootBone);
|
|
if (hipBone != null)
|
|
{
|
|
hipBone.position = pose.BodyRootPosition;
|
|
hipBone.rotation = pose.BodyRootRotation;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// HumanPose 적용
|
|
_poseHandler.SetHumanPose(ref humanPose);
|
|
|
|
_frameIndex++;
|
|
}
|
|
|
|
public void SetInstanceID(string id)
|
|
{
|
|
instanceID = id;
|
|
}
|
|
|
|
public void SetUseDontDestroyOnLoad(bool use)
|
|
{
|
|
useDontDestroyOnLoad = use;
|
|
}
|
|
|
|
public string GetInstanceID()
|
|
{
|
|
return instanceID;
|
|
}
|
|
}
|
|
} |