MMD形式キャラクターモデルの表情・頭・位置をウェブカメラで動かす

#概要
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Unityちゃん表情追加確認です。 <a href="https://t.co/UnKmy9Syar">pic.twitter.com/UnKmy9Syar</a></p>&mdash; 琴葉 葵（偽） (@Hv2RMjHzDyqXVIr) <a href="https://twitter.com/Hv2RMjHzDyqXVIr/status/886909132518838272">2017年7月17日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
こんな感じに3Dのキャラクターモデルをウェブカメラで動かします。
この記事は作成済みのUnityProjectにMMD形式のモデルを追加する手順になります。

#準備
##カメラ
ウェブカメラが必要です。
投稿者使用例：BSWHD06MBK / C270 / SR300
![IMG_20170723_171748.jpg](https://qiita-image-store.s3.amazonaws.com/0/183870/53fc60c7-4408-409c-de87-fddfc5d86db9.jpeg)

##Unity 2017.1.0f3
https://store.unity.com/ja/download?ref=personal
ダウンロードしてインストールします。
※ユーザー登録が必要です。

##RealSenseSDK 2016R3(coreとface)
https://software.intel.com/en-us/intel-realsense-sdk/download
ダウンロードしてインストールします。
![rs1.png](https://qiita-image-store.s3.amazonaws.com/0/183870/835fc241-e0db-92d7-bd09-b97cd8e9537d.png)
![rs2.png](https://qiita-image-store.s3.amazonaws.com/0/183870/1262518e-9d4a-2d7f-cce5-29ce52d3ec13.png)
※ユーザー登録が必要です。
※結構面倒です。要点だけ挙げます。
・Download的なリンクからユーザー登録ページに行って登録を済ませます。
・ページ上部にある「FREE Download」よりも若干下にある「SDK Components Download」の「Essentials」と「Face Tracking & Recognition」のリンクから入手した方が分かりやすいと思います。
・ページが大幅に変更されていた場合は……、頑張ってください！
<font color="Red">※FaceをインストールするとCore(Essentials)も自動でインストールされるようです。</font>

<b><font color="Red">
※注意※
ここで使っているRealSenseSDKの更新は停止しました。
現在Intelから通常ルートで入手できるものは別物です。
それでも使いたい方は以下から今の所DLできるみたいです。(2018/02/14)</font></b>
https://www.intel.co.jp/content/www/jp/ja/support/articles/000023988/emerging-technologies/intel-realsense-technology.html

##MMD4Mecanim
http://stereoarts.jp/
ダウンロードして置いておきます。
公開ページの「解説」にある「チュートリアル(基本編)」をやっておきましょう。
※規約やライセンスについて良く読みましょう。

##CharWebCam
https://github.com/xelloss120/CharWebCam
投稿者が作ったものです。
![git.png](https://qiita-image-store.s3.amazonaws.com/0/183870/56eb7bcc-4676-bcf4-bd59-36465af3ddfe.png)
「Clone or download」から「Download ZIP」でダウンロードします。
最初からUnityちゃん版が入っているので、動くことを確認してみましょう。
.\CharWebCam-master\CharWebCam-master\Assets\Scene.unity
から開けます。

#MMDモデルの追加
CharWebCamのProjectを開いて、MMD4Mecanimを追加します。
動かしたいモデルを追加します。(今回はプロ生ちゃんです。)
MMD4Mecanimで変換して、Sceneに追加します。
![dd.png](https://qiita-image-store.s3.amazonaws.com/0/183870/b1b80251-9b4e-466b-2072-5883e73451c1.png)

#MMD向けスクリプトの追加
.\CharWebCam-master\CharWebCam-master\MMD_Sample\
に入っている2つのファイル(スクリプト)をどこでもいいのでUnityへ追加します。
![mmdsample.png](https://qiita-image-store.s3.amazonaws.com/0/183870/66586fd0-f424-6d9c-7959-be49071be75a.png)

#MMD向けスクリプトの適用
追加したスクリプトをプロ生ちゃんに追加します。
追加されると、右側に追加された内容が表示されます。
![scriptadd.png](https://qiita-image-store.s3.amazonaws.com/0/183870/e23e0d85-2447-4034-be54-355f8af070f9.png)
※ここでAudio Sourceを追加しておきましょう。

#オブジェクトの割り当て
SceneにあるCanvasの中のTextとDetectedValueと、
.\CharWebCam-master\CharWebCam-master\Assets\CharWebCam\RGBMaterialを
画像のように割り当てます。
![objadd.png](https://qiita-image-store.s3.amazonaws.com/0/183870/7ae6063c-5f3c-7387-c158-a809624e4e08.png)

#キャラクターモデルの割り当て
上記と同様にプロ生ちゃんの体と頭を画像のように割り当てます。
![charadd2.png](https://qiita-image-store.s3.amazonaws.com/0/183870/307f46af-2967-2150-55e2-f706f85846fa.png)

#位置合わせ
プロ生ちゃんの位置を以下のように設定します。
![transform.png](https://qiita-image-store.s3.amazonaws.com/0/183870/f04a5a43-cf0b-de06-54d6-483daebcdc3b.png)

#Unityちゃんを非表示
Unityちゃんを非表示にします。
![unitychandisable.png](https://qiita-image-store.s3.amazonaws.com/0/183870/e8aab841-3b23-afb9-f257-048f529f02c6.png)

#実行確認
<font color="Red">※ここで必ず保存してください。</font>
再生ボタンorCtrl+Pで実行してみてください。
以下のような画面でキャラクターが動けば成功です。
※停止はもう一度再生ボタンorCtrl+Pです。
![sample.png](https://qiita-image-store.s3.amazonaws.com/0/183870/9113a938-1d2e-8569-c420-c8d93d6e5f86.png)
口を動かす場合は、音声入力させるデバイスを数字キーで選択してください。
右端は位置と表情の検出値です。
右下はカメラの映像です。
一応マウスのドラッグ操作でカメラの位置と角度が変更できます。
表示されている文字はESCキーで消せます。

#注意
<font color="Red">※実行を停止するタイミングでUnityがクラッシュする不具合があります。</font>
<font color="Red">※左上にデバイス一覧が正しく表示されない。または選択しても口が動かない場合は、デバイス名を全て半角英数字に変更してWindowsを再起動してみてください。</font>

#調整
名前の通り、今回使用したスクリプトは特定のモデル向けのものです。
動かしたいモデルによってはそのまま使えません。というか、多くの場合そのまま使えないと思います。
主に以下のファイルを変更するなどして対応してもらえればと思います。
.\CharWebCam-master\CharWebCam-master\MMD_Sample\RS_Kotonoha.cs

```csharp
using UnityEngine;

public class RS_Kotonoha : RealSense
{
    public GameObject Body;
    public GameObject Head;
    public GameObject EyeL;
    public GameObject EyeR;
    
    // モーフ取得のため
    MMD4MecanimModel Model;

    void Start()
    {
        EyesPosX = 20;
        EyesPosY = 7;
        BodyPosYOffset = Body.transform.position.y;

        Init();

        // 初期表情
        Model = GetComponent<MMD4MecanimModel>();
        Model.GetMorph("じと目").weight = 0.7f;
        Model.GetMorph("眼球縮小").weight = 0.2f;
    }

    void Update()
    {
        // 値が揃ってから参照
        if (!Ready)
        {
            return;
        }

        // 各パラメータ表示
        UpdateParamText();

        // 体移動
        Body.transform.position = BodyPos;

        // 頭向き
        Head.transform.localEulerAngles = new Vector3(-HeadAng.z, -HeadAng.x, HeadAng.y);

        // 視線
        Vector3 eyesAng = new Vector3(EyesPos.y, EyesPos.x, 0);
        EyeL.GetComponent<MMD4MecanimBone>().userEulerAngles = eyesAng;
        EyeR.GetComponent<MMD4MecanimBone>().userEulerAngles = eyesAng;

        // 目パチ
        Model.GetMorph("まばたき").weight = EyesClose / 100;

        // 眉上
        Model.GetMorph("上").weight = BrowRai / 100;

        // 眉下
        Model.GetMorph("下").weight = BrowLow / 100;
        Model.GetMorph("困る").weight = BrowLow / 100;
        Model.GetMorph("上まぶた閉").weight = BrowLow / 100;

        // 笑顔
        Model.GetMorph("まばたき3").weight = Smile / 100;
        Model.GetMorph("笑い").weight = Smile / 100;

        // キス
        Model.GetMorph("眼球縮小").weight = Kiss * 0.02f + 0.2f;

        // 表情競合対策
        if (Smile > 10 || BrowLow > 10)
        {
            Model.GetMorph("まばたき").weight = 0;
        }
        if(Smile > BrowLow / 2 || Kiss > BrowLow / 2)
        {
            Model.GetMorph("下").weight = 0;
            Model.GetMorph("上まぶた閉").weight = 0;
        }
        float ret = Mathf.Max(EyesClose, Mathf.Max(Smile, Mathf.Max(BrowRai, BrowLow)));
        Model.GetMorph("じと目").weight = 0.7f - (ret * 0.007f);
    }
}
```

要点としては、
見当違いな動きをする場合はXYZを入れ替える。
若干不自然な向きや表情の場合は末尾の値を調整する。
といった所です。

表情についてはモーフの登録名などが違ったりするので、サンプルを見ながらモデル毎の対応が必要です。

MMDで言う所の物理に関しては、方法が色々あるため、この機会に調べてみると良いと思います。

#参考
http://www.naturalsoftware.jp/entry/2014/10/21/071006
https://software.intel.com/sites/landingpage/realsense/camera-sdk/v2016r3/documentation/html/index.html?doc_devguide_introduction.html
http://tsubakit1.hateblo.jp/entry/2014/11/08/233000