UnityでPerception Neuronを使ってMMDモデルを動かす

#はじめに
UnityでPerception Neuronを使ってMMDモデルを動かす手順について書きます。「Perception Neuronって何？」という方は「[MMM(MikuMikuMoving)でPerception Neuronを使う](http://qiita.com/aimino/items/55e8ec706fa18581b0a1)」を先に目を通していただくとよいかと思います。

#作業の流れ
Perception Neuronの[公式サイト](https://neuronmocap.com/software/unity-sdk)でUnity向けのSDKが公開されています。基本的にはそちらのパッケージを利用すればよいのですが、Perception NeuronとMMDモデルではデフォルトポーズが異なっているため（NeuronはTスタンス、MMDモデルはAスタンス）、その部分に関して調整する必要があります。

調整する方法としては
- MMDモデルを事前にAスタンスからTスタンスに変形させる
- プログラム実行時にデフォルトポーズの違いを吸収する
という二つの方法があるかと思います。

「[MMM(MikuMikuMoving)でPerception Neuronを使う](http://qiita.com/aimino/items/55e8ec706fa18581b0a1)」では、「プログラム実行時にデフォルトポーズの違いを吸収する」方法で調整しました。ここでは「MMDモデルを事前にAスタンスからTスタンスに変形させる」方法で調整したいと思います。

#MMDモデルをTスタンスに変形させる
はじめにMMDモデルを用意します。ここでは[Tda式初音ミク](https://bowlroll.net/file/4576)を使わせていただきます。
モデルのデフォルトポーズを変形させるために[PMXエディタ](http://kkhk22.seesaa.net/category/14045227-1.html)を使用します。
MMDモデルをPMXエディタで開きましょう。
![001.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/901384e0-af09-1f88-8680-77a902095835.png)

TransformViewを開きます。
![002.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/7e573e21-2c65-6350-56a1-90d683f47a97.png)

右肩、右腕、左肩、左腕のZ軸の角度を調節してTスタンスに変形します。
![003.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/b1b3fd59-0a68-cdfe-bebb-974d1ce16f41.png)

「ファイル」→「現在の形状で保存」を選択し、適当に名前を付けて保存しましょう。
![010.png](https://qiita-image-store.s3.amazonaws.com/0/26034/4317f882-9218-0985-3e96-9d2310fb8811.png)

#MMDモデルをUnityで使用する
Noraさん([@Stereoarts](https://twitter.com/Stereoarts))のMMD4Mechanimを使うことで、UnityでMMDモデルを使うことができます。MMD4Mechanimは[Stereoarts Homepage](http://stereoarts.jp/)からダウンロードすることができます。詳しい使い方は[こちら](http://stereoarts.jp/MMD4Mecanim%20%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%EF%BC%88%E5%9F%BA%E6%9C%AC%E7%B7%A8%EF%BC%89.pdf)に載っています。

Unityで適当な名前でプロジェクトを新規作成します。
![004.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/a729822a-3018-a00e-3cb6-e99e7dccae2c.png)

エディタが開きます。
![005.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/10c07e7d-f5c5-f918-3d0d-943793cd61f9.png)

プロジェクトのAssetsフォルダの下にMMDモデルのファイル一式をコピーします。
![006.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/730563a8-dbbf-44da-16e8-44bfaa7e5370.png)

MMD4Mecanimをインポートします。
![007.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/c1a464e8-8e61-8c4c-c031-0393bfda91e9.png)

変換するMMDモデルを選択し、利用規約を確認の上Processボタンを押します。VMDは空で構いません。
![009.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/fde4450c-efc5-ce48-d279-6685aa2df19c.png)

生成されたモデルを選択し、RigのAnimation TypeをHumanoidに変更し、Applyボタンを押します。
![011.png](https://qiita-image-store.s3.amazonaws.com/0/26034/a518395f-8ad7-0265-b5ba-9fbe944692a8.png)

モデルをシーンに配置します。MMD4MechanimModelスクリプトのPhysics EngineをBullet Physicsに変更しておきましょう。
![012.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/58d9b565-670c-e353-ec08-bc7d799c8272.png)

#Perception NeuronのSDKを使用する
Perception Neuronの[公式サイト](https://neuronmocap.com/downloads)からUNITY SDKをダウンロードしましょう（2016/3/5現在UNITY SDK 0.2.5が最新版です）。ダウンロードできたらインポートします。
![013.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/a33c0e00-fe1e-17be-63ad-ffba755f5cbf.png)

下記ダイアログが表示されたら、「I Made a Backup.Go Ahead!」を選択してください。
![014.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/908bde9e-c72f-39ba-32d2-a8d9b2a35cc1.png)

Assets/Neuron/Scripts/Mocap内のNeuronAnimatorInstanceスクリプトをモデルにアタッチします。Connect To Axisにチェックを入れてください。
![015.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/97b0bae9-170c-4b20-69c9-6ff7be9d5e48.png)

#Axis Neuronの準備
Perception Neuronの[公式サイト](https://neuronmocap.com/downloads)からAxis Neuronをダウンロードしましょう（2016/3/5現在Axis Neuron 2740が最新版です）。Axis Neuron Proを持っている方はそちらでもかまいません（2016/3/5現在Axis Neuron Pro 3903が最新版です）。

SettingsのBroadcastingでBVHにチェックを入れます。
![016.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/db2edb13-d295-3010-61ff-82b3785b3394.png)

ボーンの角度情報のみを使用するため、位置情報は外す必要があります。SettingsのOutput FormatのDisplacementのチェックを外します。（Displacementにチェックが付いているとボーンの位置情報も使用されてしまうため、モデルが恐ろしいことになります。。）
![017.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/7bbdfb79-1881-bf2a-afb2-6bf9e5105d87.png)

適当なモーションを再生させておきましょう。
![018.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/7e5f45e3-e443-325a-c851-d353530f2ebe.png)

Unity側に戻って実行してみましょう。モーションが適用されていればOKです。
![019.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/f59f485b-4097-4425-6b32-bd6771aea6c4.png)

2016/3/5現在UNITY SDKにバグがあるようで、しばらく動かしてるとモデルの親指が荒ぶりだします。
![020.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/6ef5368a-5656-4316-221b-c2a20a3a26b8.png)

仕方がないので親指ボーンへの角度の設定をコメントアウトします。右親指、左親指両方ともやっておきましょう。（それでも長時間動かしてるとダメっぽいです）

```csharp:NeuronAnimatorInstance
		// right hand
		SetRotation( animator, HumanBodyBones.RightHand, actor.GetReceivedRotation( NeuronBones.RightHand ) );
//		SetRotation( animator, HumanBodyBones.RightThumbProximal, actor.GetReceivedRotation( NeuronBones.RightHandThumb1 ) );
//		SetRotation( animator, HumanBodyBones.RightThumbIntermediate, actor.GetReceivedRotation( NeuronBones.RightHandThumb2 ) );
//		SetRotation( animator, HumanBodyBones.RightThumbDistal,	actor.GetReceivedRotation( NeuronBones.RightHandThumb3 ) );
```

こんな感じになります。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">UnityでPerception Neuron&amp;MMDモデル <a href="https://t.co/HVyezazoQI">pic.twitter.com/HVyezazoQI</a></p>&mdash; aimino (@minoaimino) <a href="https://twitter.com/minoaimino/status/702529793682608128">2016年2月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

#VR対応
ついでにVR対応させてみましょう。PERCEPTION NEURON UNITY HANDBOOKの「HMD INTEGRATION」の章には次のように書かれています。

>1. The rotation tracker of the HMD should always have priority. Don’t overwrite its rotation values with something else and don’t use the head rotation values from the Perception Neuron system.
>2. Don’t use the positional tracking of the HMD.
>3. Never parent the HMD cameras or GameObjects to the skeleton setup.

※「PERCEPTION NEURON UNITY HANDBOOK」の「HMD INTEGRATION」より引用

以下の方法を推奨しているようです。
・頭の回転はHMDから取れる値を使う。Perception Neuronから取れる値は使わない。
・頭の位置はPerception Neuronから取れる値を使う。HMDのポジトラの値は使わない。

以下にVR向けのシンプルなスクリプトが用意されています。
Assets/NeuronExamples/OVRExample/NeuronOVRAdapter
PERCEPTION NEURON UNITY HANDBOOKには以下のように書かれています。

>● On every new frame we position the OVR Camera Rig to the same position as the head target object.
>● This target object is an empty GameObject inside the Head skeleton hierarchy. We use the target object to provide an easy way to define an offset and to set the correct position on the head.
>● Since we never change the rotation of the OVR Rig you need to reset its tracker once you have the HMD on your head. This way the rig will be aligned correctly with your virtual body. Make sure you’re facing forward when resetting the Oculus tracker. (Note: you need to code the reference to the OVRManager yourself in order to reset
the OVR pose).

※「PERCEPTION NEURON UNITY HANDBOOK」の「HMD INTEGRATION」より引用

頭のボーンの階層にOVRCameraTargetという名前で空のGameObjectを追加します。位置は後で微調整しましょう。
![021.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/ab1ffbe5-aff7-3d17-767d-4fd70407c43c.png)

毎フレームVRのカメラの位置をOVRCameraTargetの位置で更新するわけですが、スクリプトで直接カメラの位置や姿勢を変更してもHMDから取れる値で上書きされてしまいます。CameraControllerという名前で空のGameObjectを作って、カメラをその子にしましょう。HMDのポジトラの値を無効にするためにCameraControllerのScaleを(0,0,0)にしておきます。
![022.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/8cf81b01-1e09-33fb-f90b-327142b74af0.png)

CameraControllerにNeuronOVRAdapterをアタッチし、Bind TransformにOVRCameraTargetをセットします。
![023.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/736a3d86-0e7c-6e6b-bf87-25b33418ebbb.png)

PlayerSettingsのVirtual Reality Supportedを有効にします。
![024.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/231e27eb-b838-9e39-9eb0-02e3d4233de1.png)

カメラのClipping PlaneのNearをいい感じに調整しておきましょう。
![026.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/2a53648b-5e0b-a8cf-47ee-2e259e8d3d29.png)

せっかくなので、床とか鏡とか用意してみましょう。鏡は[これ](https://www.assetstore.unity3d.com/jp/#!/content/34824)を使わせていただきました。
![025.PNG](https://qiita-image-store.s3.amazonaws.com/0/26034/03af4c62-414b-2513-1399-7a2ca7c60406.png)

実行してみるとHMDの向きとモデルの向きが合っていません。
HMDとモデルの向きをリセットするスクリプトを作ります。適当なオブジェクトにアタッチしておきましょう。

```csharp:ResetOrientation
using UnityEngine;
using UnityEngine.VR;
using System.Collections;

public class ResetOrientation : MonoBehaviour {

    public GameObject modelRoot;
    public GameObject modelHip;
	
    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown(KeyCode.R))
        {
            InputTracking.Recenter();
            modelRoot.transform.rotation = Quaternion.Euler(0, -modelHip.transform.localRotation.eulerAngles.y, 0);
        }
    }
}
```

modelRootにはモデルのルートを、modelHipにはモデルのHipをセットしておきます。RキーでHMDもモデルも鏡の方を向きます。
![image](https://qiita-image-store.s3.amazonaws.com/0/26034/8aa0aff1-e671-bb4a-7819-b0ed1fc3fc89.png)

こんな感じになります。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Perception NeuronとOculus Riftでミクさんになって「こ、これが俺、なの、、か、、？」ってやって遊んでた。楽しかった。 <a href="https://t.co/385ymb79xX">https://t.co/385ymb79xX</a></p>&mdash; aimino (@minoaimino) <a href="https://twitter.com/minoaimino/status/705424576658825216">2016年3月3日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>