28
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Unity】スクリプトからキャラクターのボーンを制御する準備 (備忘録)

Last updated at Posted at 2018-12-19

概要

スクリプトで3Dキャラクター(Humanoid)を動かす場合、動かしたいHumanoidのavaterからHumanPoseHandler(各ボーンの状態を読み書きできるハンドラー)を作成します。
HumanPoseHandlerの値をHumanPose(各ボーンの状態が保存された構造体?)に適用し、HumanPoseを任意の値に変更した後、HumanPoseをHumanPoseHandlerにセットする事で、ボーンの変更が適用されます。
よくわからないので実際のプログラムを見ます。

サンプル

HumanAnimation.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HumanAnimation : MonoBehaviour
{
	[SerializeField]
	private Animator _animationTarget;

	private HumanPose _targetHumanPose;
	
	void Update ()
	{
		SampleAnimation();
	}

	private void SampleAnimation()
	{
		if (_animationTarget == null)
		{
			Debug.Log("Animatorがアタッチされてません");
			return;
		}
		
		// Animator avater → handler → HumanPose と渡す
		// HumanPose の値を変更して、handlerへ渡すとHumanBoneに変更が適用される。
		var handler = new HumanPoseHandler(_animationTarget.avatar, _animationTarget.transform);
		handler.GetHumanPose(ref _targetHumanPose);

		//HumanPoseを更新
		int muscles = _targetHumanPose.muscles.Length;
		for (int i = 0; i < muscles; i++)
		{
			float move = 0.02f * Time.deltaTime; //moveの係数だけ変化します
			_targetHumanPose.muscles[i] = _targetHumanPose.muscles[i] + move;
			//Debug.Log(i + " : " + _targetHumanPose.muscles[i]);
		}
		
		//変更を適用する場合… SetHumanPose で変更した HumanPose を渡す
		handler.SetHumanPose(ref _targetHumanPose);
	}

	[ContextMenu("HumanPoseの配列に対応したリグ名を表示")]
	private void ShowMuscleList()
	{
		string[] muscleName = HumanTrait.MuscleName;
		int i = 0;
		while (i < HumanTrait.MuscleCount) {
			Debug.Log(i + " : " + muscleName[i]);
			i++;
		}
	}
}

_animationTarget

ボーンの制御を行いたい3Dキャラクター(Humanoid)をアタッチします。

_targetHumanPose(HumanPose)

HumanPose - スクリプトリファレンス / HumanPoseHandler - スクリプトリファレンス
この値を変更する事で、キャラクターのボーンを変更できます。
ポイントなのが 直接ボーンのtransformを制御するわけじゃない という点です。

HumanPoseは -1~1の値が入っています。なので、扱う値は正規化済みなので色々と楽です。
→ HumanPose に Mathf.Sin(Time.deltatime * 2 * Mathf.PI * 0.1f) とか入れると周期運動する。
また、変化量の1次元情報のみを扱うので回転の処理など考える必要がありません。

_targetHumanPose.muscles[i] = _targetHumanPose.muscles[i] * 何かの係数;

というような書き方をする事ができます。
分かりやすい所でいくと _targetHumanPose.muscles[] で指のボーンを指定してやれば、係数をスライダーで変更して指を開閉させる…なんて事ができます。


var handler = new HumanPoseHandler(_animationTarget.avatar, _animationTarget.transform);
handler.GetHumanPose(ref _targetHumanPose);

HumanPoseHandlerでハンドラーをインスタンス化し、ハンドラーからHumanPoseへ参照渡しします。
最終的に変更した HumanPose(_targetHumanPose) を handler.SetHumanPose(ref _targetHumanPose); で適用してやるとキャラクターの姿勢が定まります。

ShowMuscleList()

image.png

[ContextMenu()]を書いてやると、Unityを実行しなくてもメソッドを実行できます。
この場合、HumanPoseのどの配列に何のボーンが割り当てられてるか?の一覧を表示します。

まとめ

あとは難しいベクトル計算とかして、それらの値を使ってHumanPoseを制御すると自動化などができるようになる…!
また、VRIKなどで動かしたこれらの値を、すくりぷたぶるおぶじぇくとに保存する事で疑似モーションキャプチャーを作れたりします。
高額のモーションキャプチャーであればドライバの方にモーション記録機能がついてたりしますが、ViveでVtuberをやってる人は自前でモーションキャプチャーを作ってみるのも面白いかもしれません。
(VRで演技して、第三者視点からカメラ付けとかできるので)

参考

Unity、Oculus(HTC Vive)、VRIKで簡易モーションキャプチャを作った話
UniRXで書いてあって初心者の私には読めない…

ランタイムでAvatarを生成してアニメーションに利用する

Animator - スクリプトリファレンス

28
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?