iPhoneX で顔トラッキングをして Unity で BlendShapes を動かし vtuber を目指す

漢なら iPhoneX + Unity で face tracking して vtuber 目指したいですね!

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">ねんがんの iPhone X + Unity での facial capture アプリの実行に成功したぞ!!!! 🎉🎉🎉🎉🎉🎉😤😤😤😤😤😤✌️✌️✌️✌️✌️✌️㊗️㊗️㊗️㊗️㊗️㊗️😎😎😎😎😎😎😎 &gt; <a href="https://t.co/ALwQN3YiVq">https://t.co/ALwQN3YiVq</a> <a href="https://t.co/JXQ9nGAM8O">pic.twitter.com/JXQ9nGAM8O</a></p>&mdash; Syoyo Fujita (@syoyo) <a href="https://twitter.com/syoyo/status/987938436471377925?ref_src=twsrc%5Etfw">April 22, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

やりましょう!


## 準備

* iPhoneX と XCode 開発環境と https://github.com/johnjcsmith/iPhoneMoCapiOS
* Unity(2017.2 or later) と https://github.com/johnjcsmith/iPhoneMoCapUnity
* iPhoneX と Unity を動かす PC(Windows だとうまくいなかったので, mac のほうがネットワーク接続問題がなさそう)が同一ネットワーク(wifi) 環境にあること. 

## 仕組み

iPhoneX の face tracking SDK により BlendShapes のウェイトを取得できます.
(ちなみに, face tracking 自体はふつうのカメラ画像からやっているっぽくて赤外線センサーを隠しても認識します. Apple 側で iPhoneX でのみ動作するように制限がかかっています)

 iPhoneMoCapiOS では, その BlendShapes の重みを UDP で Unity に飛ばし(テキストにして送信), Unity でそのデータを受け取り BlendShapes をコントロールします.

## セットアップ

iPhoneMocapiOS を XCode でビルドして iPhoneX にインストールしておきます.

Unity で iPhoneMoCapUnity のデータを読み込みます. Unity と iPhoneMoCapUnity のバージョン違が違うとロードがうまくいかないようなので, 必要に応じて, 一旦 Asset を Hierarchy に再インポートします.

Unity 側では, ネットワークが同一環境にない場合は Unity 側のネットワーク UDP アドレスを調整ください.
(たとえば `192.168.10.xxx` の IP アドレスなら, ブロードキャストアドレスとして `192.168.10.255` など)

UDPServer.cs で boardCastIP を必要に応じて自分のブロードキャストアドレスに変更します.

```
private static IPEndPoint broadCastIP = new IPEndPoint(IPAddress.Parse("192.168.10.255"), 49452); 
```

また, いろいろ変えたら iPhoneX 側のアプリを再起動しましょう(以前のネットワーク設定での connection が残って, Unity 側と繋がらなくなったりする)

## ユーザ作成の BlendShapes を動かす.

Maya で BlendShapes を作るものとします. 

Blender でも形式を合わせればいけるかもしれません.

BlendShapes に詳しい優秀な BlendShapes アーティスト若人を探しましょう!

各シェイプの名前(e.g. `eyeBlinkLeft`)は iPhoneX face tracker の名前と合わせます.

https://developer.apple.com/documentation/arkit/arfaceanchor.blendshapelocation
 
iPhoneMoCapUnity に付属の JohnSmithHead.fbx を Maya に読み込んでノード名などを確認して BlendShapes データを作るとよいでしょう.

出来上がったら FBX でエクスポートします.

### Unity で読み込む

Unity 側で読んだ Asset を Hierarchy にインポートしたときに, 名称を `BlendShapeTarget` に変更しておきます.
もしくは, NetworkMeshAnimator で GameObject.Find("BlendShapeTarget")のところを変えます.

```
	public void StartAcceptingMessages() {
		Debug.Log("Started accepting messages");

		meshTarget = GameObject.Find ("BlendShapeTarget").GetComponent<SkinnedMeshRenderer> ();
```

### Shape 名の対応

エクスポートの仕方が悪いのか, FBX を Unity で読むと
`blendShape1.eyeBlinkLeft` などと, Maya の親?ノード名(`blendShape1.`) プレフィックスがついてしまいます.

<img width="575" alt="Screen Shot 2018-04-23 at 18.01.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/36275/37e5c385-8647-30dc-d4f3-10a82f86a8db.png">


Unity のエディタ側でノード名を修正する機能はないため, とりあえずは C# スクリプトを修正することで対応します.

NetworkMeshAnimator.cs の SetBlendShapesOnMainThread で, 以下のように prefix をくっつけます.

```
				var mappedShapeName = strArray.GetValue (0).ToString ().Replace ("_L", "Left").Replace ("_R", "Right");

				// HACK
				mappedShapeName = "blendShape1." + mappedShapeName;
```

これで自分が作った BlendShapes をアニメートすることができます!

Happy vtuber developing!

## TODO

* FBX で BlendShape 名に prefix がつかないようにする方法を探す.
* 顔の傾きなどの情報も扱えるようにする
* 物理エンジン?
* Blender と連携したい
* 優秀な若人さまが, 人類史上最速で iPhoneX + Unity で BlendShapes と face tracking を極め, 1 億総 vtuber 活躍社会を実現するスキームを確立する旅に出たい.