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

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

### サンプル

```C#: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)

<a target=”_blank” href="https://docs.unity3d.com/ja/2017.4/ScriptReference/HumanPose.html">HumanPose - スクリプトリファレンス</a> / <a target=”_blank” href="https://docs.unity3d.com/ja/2017.4/ScriptReference/HumanPoseHandler.html">HumanPoseHandler - スクリプトリファレンス</a>
この値を変更する事で、キャラクターのボーンを変更できます。
ポイントなのが **直接ボーンのtransformを制御するわけじゃない** という点です。

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


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

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

```C#:

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

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

#### ShowMuscleList()

![image.png](https://qiita-image-store.s3.amazonaws.com/0/149449/b9c262af-86f4-06b5-ec06-e53f1416320b.png)

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

### まとめ

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

### 参考

<a target=”_blank” href="https://qiita.com/UnagiHuman/items/3517a3e28fb8cba1de3b">Unity、Oculus(HTC Vive)、VRIKで簡易モーションキャプチャを作った話</a>
UniRXで書いてあって初心者の私には読めない…

<a target=”_blank” href="http://edom18.hateblo.jp/entry/2017/12/09/105126">ランタイムでAvatarを生成してアニメーションに利用する</a>

<a target=”_blank” href="https://docs.unity3d.com/ja/current/ScriptReference/Animator.html">Animator - スクリプトリファレンス</a>