Kinectを使って身振り手振りもできるバーチャル美少女おぢさんになる

# Kinectを使って身振り手振りもできるバーチャル美少女おぢさんになる

※かなりゆるい記事になるので肩の力を抜いて読んでもらえるとです
※Windows向けの内容になります

## きっかけ
2月下旬にコロナにより、在宅勤務による移行が行われました。
現在まで続いており、仕事自体は快適にできております。
ゲーム会社で働く社員としては、やはり遊び心がほしいところです。
なので早いうちにビデオ通話にバ美肉にをしたいと考えました。
バ美肉やりたかったのは~~女の子になりたい~~なんとなくです。
はい、きっかけなんて些細なものです。

## 最初にやったこと
最初はスマホのフェイストラッキングアプリを使いました。
自分もiPhoneXを持ってるので
背景をグリーンスクリーンにしてOBSで合成して作業しました。
最初試してたのは以下の２つ
[カスタムキャスト](https://customcast.jp/)
[Reality](https://reality.app/)
他にもたくさんありましたが
Realityの見た目が好みだったのでしばらく使ってました。
![babi.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/9f9412a6-be3a-42ff-b256-10854855d1a2.gif)
画像の感じで6月ぐらいまで毎日を過ごしてました

ただ、やはり物足りない・・・
顔だけでも表情や視線などあって十分だと思ったのですが
やはり身振り手振りしたいです。
ということで自前で作ろうとなりますた。

## 全身トラッキングしたい
自前で作る上で必要になるものは以下の物が必要だなと考えました。

* 全身をトラッキングするデバイス
* 3Dモデル
* 制御するソフト

ソフトはとりあえずUnityでやろうと考えて
後は、とりあえずそれぞれどうするか調査していきました。

#### 全身をトラッキングするデバイス
ちょうどお家にKinect v2があったのでこれを利用しようと思いました。
[Kinect for Windows v2なので現在は販売停止してます](https://japanese.engadget.com/jp-2015-04-03-ms.html?guccounter=1&guce_referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8&guce_referrer_sig=AQAAAKzltGMAfwDtsWOAVGzjGw8J7zwtvyzI8WybceWZ0uPXRpvxwmqMJXDLgzVRYtt2aSwuv8y7Gj6QG03RvNUrQtQi3g6z4yFIVVXOWucYggH5ZIV5_zbZwAB4bnxWWZpcbIaXquHq6cYzURrtApKjZ_rHczIqwxnfEcOLuCJM3gAI)が多分皆さんのご家庭にも一台必ずあると思うので問題ないはず
もしなかったら代わりに[Azure KinectDK](https://azure.microsoft.com/ja-jp/services/kinect-dk/)が後継機でありますがSDK周りがKinectV2と異なるので今回やるバ美肉のやり方を流用できないかもしれないので注意です。
ちょい値段もv2より上がってるので自分はDKでなくなったら買おうかなと思ってます。

Kinect for Windows v2はSDKがあるので利用する前に[SDKも入れます](https://www.microsoft.com/en-us/download/details.aspx?id=44561)

#### 3Dモデル
せっかく美少女になるので見た目の可愛い子を選びました。
[スノウエルフお嬢様](https://booth.pm/ja/items/1202638)が可愛かったのでこの娘にしました。
有料ですが可愛かったので後悔してないです。
ファイル形式はunitypackageとfbxだったので取り込みやすかったです。

8月ぐらいまでの利用してましたがだんだんと
**自分でデザインしたい**
欲が出てきて自分で見た目も作りたくなりました。
[VRoid Studio](https://vroid.com/studio)がすごい使いやすくて
こちらを利用することにしました。

見た目を変えるのに以下のデータを購入して活用させていただきました。
[【VRoid】ビビ セルルックアニメ風改変モデル](https://booth.pm/ja/items/2166187)
[【VRoid】クロップドパーカーセット【セルルック対応】](https://booth.pm/ja/items/2379743)

髪型もJsonで管理されてるので[ツール利用](http://blog.livedoor.jp/ririlseal/archives/51938803.html)して複数の髪型を合成しました。
こちらはエクスポートしたVRMモデルを扱いました。
VRMをUnityで使う際には変換する必要があります。
こちらもめちゃくちゃ便利な[UniVRM](https://github.com/vrm-c/UniVRM)があるのでこちらを使ました。

#### 制御するソフト
ソフトはUnityで作ります。
バージョンは2019.4.7f1です。
ローコストで片手間な感じで作りたいので以下のアセットを購入しました。
[Kinect v2 Examples with MS-SDK
](https://assetstore.unity.com/packages/3d/characters/kinect-v2-examples-with-ms-sdk-18708)
もし1から制作したい場合は[こちらの記事](https://www.buildinsider.net/small/bookkinectv2/0601)を参考にしてもらえるとです。

今回は上記のアセットを元に改変/拡張して進めました。

簡単な流れと注意点を以下書いていきます。
モデルは[VRoid Studio](https://vroid.com/studio)で作ったVRMデータを使います。
モデルの作り方とかはググってください。
デフォルトのモデルもかなり可愛いのでそのままエクスポートしてもいいかもです。
[UniVRM](https://github.com/vrm-c/UniVRM)も入れておきます。

VRoidStudioでエクスポートしたモデルをUnityProjectドラッグ・アンド・ドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/d26e0d69-9ac9-ec1b-efac-95ea0e202fea.png)

するとVRMのモデルがprefabとしてインポートされるので
シーンに配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/a53ee29b-89e8-92a6-e47a-adf3a3ccd533.png)

そしてインポートしたデータにAvatarControllerを配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/d1a68661-5d8f-fbf7-d5ec-78aa6b5529f4.png)

続いてKinectControllerという空オブジェクトを作ります。
KinectManager/KinectGestures/FacetrackingMangerを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/d31b7e59-0988-3ac6-2d43-61404e005999.png)

これで再生すると動きます。
![babi4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/20772649-5e2c-b685-b04a-2847ab575a19.gif)

カメラを調整してSkyboxをGreenにすれば出来上がり！
おわり！
・・・嘘です。もうちょっとだけやります。

このままだと足がプルプルしてしまいますので
足回りのトラッキングだけ除外します。

以下のファイルの533行目に入れると足のトラッキングを停止させられます。

```c#:AvatorController.cs
				if (joint == KinectInterop.JointType.HipLeft || joint == KinectInterop.JointType.HipRight ||
				    joint == KinectInterop.JointType.KneeLeft || joint == KinectInterop.JointType.KneeRight ||
				    joint == KinectInterop.JointType.FootLeft || joint == KinectInterop.JointType.FootRight)
				{
					continue;
				}

```

![babi5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/dfc8ad39-7192-0edd-efe4-089c3d988903.gif)

コードを入れるとこんな感じでトラッキングしなくなると思います。


続いて表情がないと思います。
これも簡単に口パクを実装しましょう。
BlendShapeFaceController.csがあるのでこれベースに
VRMのモーフに置き換えと必要なもの最小限に置き換えておきます。

```C#:FaceController.cs
using UnityEngine;

public class FaceController : MonoBehaviour 
{

	public SkinnedMeshRenderer faceMesh;

	private FacetrackingManager manager;
	private int jaw;
	private int eyeLeft;
	private int eyeRight;

	string Prefix = "Face.M_F00_000_00_Fcl_";

	void Start()
	{
		jaw = faceMesh.sharedMesh.GetBlendShapeIndex(Prefix+"MTH_Joy");
		eyeLeft = faceMesh.sharedMesh.GetBlendShapeIndex(Prefix+"EYE_Joy_L");
		eyeRight = faceMesh.sharedMesh.GetBlendShapeIndex(Prefix+"EYE_Joy_R");

	}
	
	void Update() 
	{
		// get the face-tracking manager instance
		if(manager == null)
		{
			manager = FacetrackingManager.Instance;
		}

		if(manager && manager.GetFaceTrackingID() != 0)
		{
			// AU1 - Jaw Lowerer
			// 0=closed; 1=fully open; -1= closed, like 0
			float fAU1 = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.JawOpen);
			fAU1 *= 200;
			faceMesh.SetBlendShapeWeight(jaw, Mathf.Clamp(fAU1,0,70));
			
			// AU6, AU7 – Eyelid closed
			// 0=neutral; -1=raised; +1=fully lowered
			float fAU6_left = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LefteyeClosed);
			fAU6_left = fAU6_left <= 0.3f ? 0 : fAU6_left;
			fAU6_left = fAU6_left >= 0.55f ? 1 : fAU6_left;
			fAU6_left *= 100;

			float fAU6_right = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.RighteyeClosed);
			fAU6_right = fAU6_right <= 0.3f ? 0 : fAU6_left;
			fAU6_right = fAU6_right >= 0.55f ? 1 : fAU6_left;
			fAU6_right *= 100;
			faceMesh.SetBlendShapeWeight(eyeLeft, Mathf.Min(Mathf.Clamp(fAU6_right,0,100),Mathf.Clamp(fAU6_left,0,100)));
			faceMesh.SetBlendShapeWeight(eyeRight, Mathf.Min(Mathf.Clamp(fAU6_right,0,100),Mathf.Clamp(fAU6_left,0,100)));

		}
	}

}


```
上記のスクリプトを配置してるVRMに貼り付けるとトラッキングするようになります。
![babi6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/1fe8fb26-1797-415d-f9b8-47057bef575f.gif)

これでリリースビルドにしてバイナリを作って
OBSでキャプチャすれば完成です！


最後に音声も認識したいので実装しました。
OVRLipsyncを利用して実装しました。
[こちらの記事](https://bibinbaleo.hatenablog.com/entry/2020/07/17/171658)を参考に実装を進めました
こちらも合わせるとかなり複雑な口の動きが再現できるようになります。

また瞬きはランダムで瞬くようにしました。
[こちらの記事](https://qiita.com/toiro/items/fbcbc168f942dca272ae)のものを利用させていただきてます。


## 最後に
プレゼンするときはOBSも駆使してこんな感じで現在やってます。
ただこれは特別な場のときのみですね。
![babi3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/b6c5ed9c-0a8d-1287-f76c-d210687138dc.gif)

発表中にこんな感じでKinectのハンドトラッキングでものを握って説明したこともありました。
![babi8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/54990473-31af-7364-71dd-a1b4cb945ae9.gif)


普段のビデオ通話ではこんな感じでラフになってます。
背景は自分の部屋を撮影してバーチャル背景にしてます。

![babi2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/f384b28b-66e6-ca8c-af2a-7884a628a4d0.gif)

他にもトラッキングができなくなったら
離席で扱うようにして離席時をわかりやすくしました。
ただ冬になってから椅子にかけてるコートが誤認されてるようで
動作しないときがちょいちょいあります。
特にコートや洗濯物は誤動作不可避のようで人物がいてもよく誤認されてしまいます。
![babi7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178782/3d5d009d-b527-3a94-6d15-a1654ec79aaa.gif)


以上になりますが
みなさんも良い美少女ライフを送ってもらえるとです！