2025-04-25 21:14:54 +09:00

170 lines
5.4 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;
private HumanPoseHandler _poseHandler;
private Action _onPlayFinish;
private float _playingTime;
private void Awake()
{
if (_animator == null)
{
Debug.LogError("MotionDataPlayerにanimatorがセットされていません。MotionDataPlayerを削除します。");
Destroy(this);
return;
}
_poseHandler = new HumanPoseHandler(_animator.avatar, _animator.transform);
_onPlayFinish += StopMotion;
}
// Update is called once per frame
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;
}
_playingTime = _startFrame * (Time.deltaTime / 1f);
_frameIndex = _startFrame;
_playing = true;
}
/// <summary>
/// モーションデータ再生終了。フレーム数が最後になっても自動で呼ばれる
/// </summary>
private void StopMotion()
{
if (!_playing)
{
return;
}
_playingTime = 0f;
_frameIndex = _startFrame;
_playing = false;
}
private void SetHumanPose()
{
var pose = new HumanPose();
pose.muscles = RecordedMotionData.Poses[_frameIndex].Muscles;
_poseHandler.SetHumanPose(ref pose);
pose.bodyPosition = RecordedMotionData.Poses[_frameIndex].BodyPosition;
pose.bodyRotation = RecordedMotionData.Poses[_frameIndex].BodyRotation;
switch (_rootBoneSystem)
{
case MotionDataSettings.Rootbonesystem.Objectroot:
//_animator.transform.localPosition = RecordedMotionData.Poses[_frameIndex].BodyRootPosition;
//_animator.transform.localRotation = RecordedMotionData.Poses[_frameIndex].BodyRootRotation;
break;
case MotionDataSettings.Rootbonesystem.Hipbone:
pose.bodyPosition = RecordedMotionData.Poses[_frameIndex].BodyPosition;
pose.bodyRotation = RecordedMotionData.Poses[_frameIndex].BodyRotation;
_animator.GetBoneTransform(_targetRootBone).position = RecordedMotionData.Poses[_frameIndex].BodyRootPosition;
_animator.GetBoneTransform(_targetRootBone).rotation = RecordedMotionData.Poses[_frameIndex].BodyRootRotation;
break;
default:
throw new ArgumentOutOfRangeException();
}
//処理落ちしたモーションデータの再生速度調整
if (_playingTime > RecordedMotionData.Poses[_frameIndex].Time)
{
_frameIndex++;
}
if (_frameIndex == RecordedMotionData.Poses.Count - 1)
{
if (_onPlayFinish != null)
{
_onPlayFinish();
}
}
}
}
}