VRMのロード、表情をつける、とか。

#はじめに
こんにちは、先日VRMを使ってYoutubeの文章スクロール系ゴシップ動画のクソサムネ風の画像を生成するソフトを作ってみました。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">期末試験直前に気が狂ってしまい、VRMを使って例の「衝撃発言に一同驚愕シリーズ」のサムネを生成することができるソフトを作りました。<br>俺は一体何やってるんだ… <a href="https://t.co/8SA2uxdH7G">pic.twitter.com/8SA2uxdH7G</a></p>&mdash; 避雷 (@lucknknock) <a href="https://twitter.com/lucknknock/status/1083773084530663424?ref_src=twsrc%5Etfw">2019年1月11日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ダウンロードは[こちら](https://booth.pm/ja/items/1173968)から

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">最終的にコレが出来上がる…許してくれ… <a href="https://t.co/oo2mkKEmUP">pic.twitter.com/oo2mkKEmUP</a></p>&mdash; 避雷 (@lucknknock) <a href="https://twitter.com/lucknknock/status/1083773426077036545?ref_src=twsrc%5Etfw">2019年1月11日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

絶対言ってないだろこんなこと。
この際VRMのロード、アニメーションなどの動的な扱いを勉強したのでその知見を公開します。入門記事しか書けない…
#VRMのロード周り
えむにわ先生の[VRMLoadUI](https://github.com/m2wasabi/VRMLoaderUI)を利用しました。何故か僕の環境だと本番環境でファイルブラウザが動作しなかったので今回は[RuntimeFileBrowser](https://assetstore.unity.com/packages/tools/gui/runtime-file-browser-113006)を利用してファイルブラウズに関する部分を一部書き換えることにします。Unityのウィンドウ上で完結するので便利。
UniRxを使ってファイルをブラウズしてパスを返す部分だけ書き換えて元のラインに返します。
(具体的にはAsyncとFileDialogForWindowsを使っているOpenVRMを後述のOpenVRMWithSimpleLoaderで置き換えます。)
![2aee8669-9c3e-40c6-b669-bf0743ee27f3_scaled.jpg](https://qiita-image-store.s3.amazonaws.com/0/256231/59d57385-8cfa-cf82-940d-8ff4d756baa7.jpeg)
↑こんな感じのUIがUnityのウィンドウ内で生成して返り値でurlを得ることができます。非同期実行。
##ファイルブラウザの設定をする
ファイルブラウザに関する様々な設定を行います。具体的には.vrmに限定する、といった絞り込みの設定をします。
名前空間は

```C#
using SimpleFileBrowser;
```

です。

```C#
FileBrowser.SetFilters( true, new FileBrowser.Filter( "VRM", ".vrm"));
```

でVRMファイルのみをブラウザできる絞り込みを追加することができます。

```C#
FileBrowser.SetDefaultFilter( ".vrm" );
```

で初期のフィルタを設定することができます。この場合は.vrmファイルとフォルダのみを表示してくれます。
これらを使ってOpenVRMのファイルブラウザを開く部分を書き換えてみると、

```C#
        public void OpenVRMWithSimpleLoader()
        {
            FileBrowser.SetFilters(true, new FileBrowser.Filter("VRM", ".vrm"));
            FileBrowser.SetDefaultFilter(".vrm");
            FileBrowser.AddQuickLink("Users", "C:\\Users", null);
            StartCoroutine(ShowLoadDialogCoroutine());
        }
```

ShowDialogCoroutine()は後述するメソッドで、実際にファイルブラウザを開く部分を担当しています。
##VRMモデルのパスを取得

```C#
	IEnumerator ShowLoadDialogCoroutine()
	{
		yield return FileBrowser.WaitForLoadDialog( false, null, "Load File", "Load" );
		Debug.Log( FileBrowser.Success + " " + FileBrowser.Result );
	}
```

`yield return FileBrowser.WaitForLoadDialog( false, null, "Load File", "Load" );`でファイル選択画面を開くことができます。取得したパスは`FileBrowser.Result`で取得できます。取得したVRMファイルのパスをwwwにぶち込んでデータを取得します。www自体非同期なのでIEnumeratorで実行しましょう。
最後に取得したパスをbyte形式にして本来のラインに戻してやります。

``` C#
            var www = new WWW("file:///" + FileBrowser.Result);
            yield return www;
            LoadVRM(www.bytes);
```

WWWは初期化時のパスの頭に"file:///"とつけることでweb上ではなく自分のPC内用のファイルパスを生成してくれます。非同期なのでyield returnすることを忘れずに。
ここまですればVRMLoaderUI側でVRMモデルをロードしてくれます。
これらをまとめると、

```C#
        IEnumerator ShowLoadDialogCoroutine()
        {
            yield return FileBrowser.WaitForLoadDialog(false, null, "Load File", "Load");

            Debug.Log(FileBrowser.Success + " " + FileBrowser.Result);
            var www = new WWW("file:///" + FileBrowser.Result);
            yield return www;
            LoadVRM(www.bytes);
            
        }
```

という感じになります。
ボタンを押下した際にOpenVRMの代わりにOpenVRMWithSimpleFileLoaderで書き換えてあげればOKです。
#VRMに表情をつける
アニメーションをつけるところでVRMの本領が発揮されます。インスタンスしたVRMモデルから動的に要素を取得しなくてはいけないのですが、なかなか簡単です。
##ボーンの制御
VRMの便利な点としてアバターごとにバラバラな表情のボーンとかをいい感じにまとめて制御してくれる、というのがあります。

これらのパラメータを弄るだけでモデル制作者側が用意した表情をそのまま使うことができます。モデル制作者側のこだわりとソフト制作者側の利便性を共存させててエモいですね。
![キャプチャ136.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/45111f5b-62dc-e3e7-7f70-61191f8caa84.png)

Joy(喜)、Angry(怒)、Sorrow(哀)、Fun(楽)、母音(A,I,U,E,O)などの顔にすることができます。
喜
![キャプチャ137.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/3d2e5750-0c04-9679-b490-4f9d540e0707.png)
怒
![キャプチャ138.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/c4175e79-cd27-e6d6-2b01-d9b37b331251.png)
哀
![キャプチャ139.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/925c51c5-37a8-f124-36b7-2af26c47e1ee.png)
楽
![キャプチャ140.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/ca2ac014-fbb8-4a4e-9b50-82d7827f8fa9.png)
(カワF～～)
VRMBlendShapeProxyにこれらのブレンドシェイプのデータが入っているのでこれを弄って喜怒哀楽の表現を出しましょう。VRMBlendShapeProxy自体はVRMオブジェクトに入っています。

```C#
        vbsp = VRM.GetComponent<VRMBlendShapeProxy>();
//喜
        var j = new KeyValuePair<BlendShapePreset, float>(BlendShapePreset.Joy,1);
        vbsp.SetValue(j.Key,j.Value);
//怒
        var a = new KeyValuePair<BlendShapePreset, float>(BlendShapePreset.Angry,1);
        vbsp.SetValue(a.Key,a.Value);
//哀
        var s = new KeyValuePair<BlendShapePreset, float>(BlendShapePreset.Sorrow,1);
        vbsp.SetValue(s.Key,s.Value);
//楽
        var f = new KeyValuePair<BlendShapePreset, float>(BlendShapePreset.Fun,1);
        vbsp.SetValue(f.Key,f.Value);
```
f.valueの値は[0,1]で自由に取れるのですが、表情を切り替える際に他の表情のキーの値を下げておくことを忘れないようにしましょう。(例えば、「怒」から「楽」に表情を変える際に「怒」のキーの値を下げておきましょう。)
##VRMにアニメーションをつける
VRMである時点でHumanoidのアニメーションを使用できることが保証されているのもVRMの利点の一つです。適当なアニメーションを流し込んでみましょう。
AnimatorもVRMオブジェクトにアタッチされています。
```C#
var vanim = VRM.GetComponent<Animator>();
vanim.runtimeAnimatorController = m_animationController;//ここに張り付けたいAnimatorを設定
```

表示名(Controller)と内部の呼び名(runtimeAnimatorController)が違うことに注意です(何故かここですごく詰まった)。
あとはvanimに対しパラメータの変更等を行えば通常通りアニメーションが動きます。
#最後に
VRM、便利ですね、クソアプリじゃなくてまともなコンテンツに使っていきたいです。 ~~これVRoidHubが来たら要らない知見になるんじゃ…~~
#参考文献
[VRMLoaderUI 0.2 リリース](https://m2wasabi.hatenablog.com/entry/2018/11/12/045811)
[RuntimeFileBrowser](https://github.com/yasirkula/UnitySimpleFileBrowser)