Unity＋OculusRiftでVRMモデルを動かしてみる


#はじめに
Unityも3Dも初心者のプログラマーが、Unity＋OculusRiftでVRMモデルを動かしてみました。
今回はとりあえず、基本的なアバター操作ができるところまで挑戦していきます。
記事作成にあたり、下記記事を参考にさせて頂いています。
なお参考にさせて頂いたところ以外は、ほぼ試行錯誤で制作したので、誤っているところや、他の良い方法等、指摘していただければ幸いです。


>Oculus LiftとFinalIKを使ってバーチャルYoutuberになる方法
https://qiita.com/ngron/items/f90ace8cb84f3aebaa5f
>【Unity】Oculus RiftとFinalIKを使ってUnityちゃんになる。
https://qiita.com/nyu___nS/items/b4658afc849f8906afb0#_reference-46753955561e612eaccd
>Final IK の VRIK の Solver にある各値の説明
https://qiita.com/_karukaru_/items/b74bb5bdf08f5de32d0e
Oculus Utilities for Unity [翻訳] [Oculus公式]
https://qiita.com/rykgy/items/265b836d4826575b0ac2

#環境
詳細な環境は下記のとおり、OculusRift／Unity／FinalIK／VRMフォーマットモデルです。
要するに個人でも簡単に揃えることが可能で単純な組み合わせです。　

<dl>
  <dt>Oculus Rift</dt>
  <dd>元々ゲームプレイ用に購入したので、HtcViviより安価なのでこちらにしましたが、</dd>
  <dd>アバターを自分で動かすなら目的ならトラッカーのあるViviの方が多分良いかと。</dd>
  <dt>Unity 2018.2.13f1</dt>
  <dd>記事作成時の最新バージョンです。</dd>
  <dt>Oculus Integration Ver1.30.1</dt>
  <dd>参考にさせて頂いた記事では"Oculus Utilities for Unity"でした。 </dd>
  <dd>名称と構成が変更されたのかと思われます。</dd>
  <dt>FinalIK Ver1.70</dt>
  <dd>骨格モデルAssetです。$90で購入。</dd>
  <dt>インサイドちゃん</dt>
  <dd>今回モデルに使わせて頂いたゲーム総合情報サイトのバーチャルレポーター</dd>
  <dd>VRMフォーマットです。(最近Mk2も登場、Mk1は髪型が変わった) </dd>
  <dt>UniVRM Ver0.44</dt>
  <dd>VRMフォーマットをUnityで利用可能なように変換してくれるAssetです。</dd>
</dl>

Unity、及びAsset Store以外のダウンロード先は下記です。
**インサイドちゃん：**　[https://3d.nicovideo.jp/works/td38514](URL:インサイドちゃん)
**UniVRM：**　[https://github.com/dwango/UniVRM/releases](URL:UniVRM)

VRMの仕様は下記にあります。
**VRM：** [https://dwango.github.io/vrm/](URL:VRM)

#概要
下記順で制作していきます。

1.各Assetのインポート。
2.シーンの下準備
3.VRMモデルをUnity用に変換
4.OVRCameraRigの配置と、トラッキングスペースの準備
5.VRIKのアタッチ
6.カメラの設置
7.コントローラによるカメラの操作
8.微調整

#各Assetのインポート
各Assetをインポートします。
Oculus IntegrationとFinalIKはAssetStoreタブから検索して、ページからインポート選択。
ダイアログが表示されるのでImportボタンでProjectに取り込まれます
UniVRMは上記GitHabのサイトからダウンロードして、UnityEditorで開けば、同様にインポートできます。

#シーンの下準備
モデルを配置するための床と背後の壁を作成しておきました。
Cubeで下記設定にて作成して配置します。
![001.png](https://qiita-image-store.s3.amazonaws.com/0/187536/50346ed3-0f6b-0416-d9f7-73d69ffa21ae.png)

#VRMモデルをUnity用に変換
VRMモデルからUnity用は、下記図のように、VRMファイルを"/Assets"に配置するだけで、UniVRMが変換してPrefab化してくれます。
変換されたモデルは分かりやいフォルダに移動しています。
![002.png](https://qiita-image-store.s3.amazonaws.com/0/187536/d85ff5b1-8ec8-f13b-6c1d-cfae9b6cd6ad.png)
![003.png](https://qiita-image-store.s3.amazonaws.com/0/187536/57662d37-8b8f-a480-c626-a012a45074ec.png)

#OVRCameraRigの配置と、トラッキングスペースの準備
ここは参考にさせて頂いた記事とほぼ同様です。
モデル、続けてOVRCameraRigをSceneに配置します。OVRCameraRigの位置はモデルの目線の位置に合わせます。
![004.png](https://qiita-image-store.s3.amazonaws.com/0/187536/cf14726e-c9bc-450d-84e6-429dfd1093e2.png)
![005.png](https://qiita-image-store.s3.amazonaws.com/0/187536/65488588-ab35-b86f-030f-b080197af352.png)
次にヘッドセット、OculusTouch左、OculusTouch右をトラッキングスペースに設定します。
トラッキングスペース下の各アンカーに、空のGameObjectを作成します。
![006.png](https://qiita-image-store.s3.amazonaws.com/0/187536/faed156d-f77f-5101-2a23-cb9764971918.png)
ゲームオブジェクトは、FinalIKの骨格モデルにあわせて、角度調整必要です。
左のGameObjectをY-90、右のGameObjectをY+90に設定します。
![008.png](https://qiita-image-store.s3.amazonaws.com/0/187536/5f2c457c-bb64-1d92-82fb-029aadc18164.png)

#VRIKのアタッチ

ここも参考にさせて頂いた記事とほぼ同様です。
FinalIKのVRIKスクリプトをモデルにアタッチします。
さらに先程作成したGameObjectをVRIKの対応するTargetに設定していきます。
![007.png](https://qiita-image-store.s3.amazonaws.com/0/187536/3085985d-9827-80eb-a34a-295d2c62dc80.png)
![009.png](https://qiita-image-store.s3.amazonaws.com/0/187536/42680e86-5ab3-4bbf-8615-7bbb0768fa08.png)

#カメラの設置

ディスプレイ上で表示を確認するためのカメラを準備します。(初期配置されたMainCameraをそのまま使用しています。)
Target EyeをNone、Audio Listenerを外します。
カメラに下記スクリプトをアタッチしてOculus側の映像をディスプレイにミラーしないように設定します。
配置したカメラはモデルの方向に回転して位置調整します。
![010.png](https://qiita-image-store.s3.amazonaws.com/0/187536/2d2a657f-9e7e-40e5-f6ed-f9c35a68e555.png)

```C#:VRmirrorSetting.cs
using UnityEngine;
public class VRmirrorSetting : MonoBehaviour 
{
	void Start () {
	  UnityEngine.XR.XRSettings.showDeviceView = false;  	
	}
}
```
![011.png](https://qiita-image-store.s3.amazonaws.com/0/187536/0609390d-4ecc-a59b-79c4-786ab1d8a797.png)



もう一点、このままではヘッドセットを装着した場合、当然自分を確認できません。
そこで鏡のように、自分の前面にカメラのテクスチャを貼り付けたパネルを準備して、確認できるようにしてみました。
1.RenderTextureを作成します。
2.メインカメラの、TargetTextureに先のRenderTextureを設定します。(下記図では新しいカメラを作成していますがメインカメラでよいです。)
3.表示本体用Quadを作成してRenderTextureをアタッチします。
![012.png](https://qiita-image-store.s3.amazonaws.com/0/187536/374d69e0-04ef-c98c-f265-32718241420c.png)
![013.png](https://qiita-image-store.s3.amazonaws.com/0/187536/c2dd5879-95e1-f1e6-3834-157d9bcd9dcb.png)
![014.png](https://qiita-image-store.s3.amazonaws.com/0/187536/8d26a3af-1d2f-1af8-39b6-ef918dec506a.png)
![015.png](https://qiita-image-store.s3.amazonaws.com/0/187536/8875a9ab-a52c-dbb1-1dbe-91d1a452f44f.png)


#コントローラによるカメラの操作

ヘッドセット内にて、四方から自分を確認しつつ調整できるように、カメラの位置変更をコントローラに設定してみます。
４方向位置固定で90度ずつカメラを回転するスクリプトを、Oculus Touchコントローラー の"A"ボタンに割当てます。
スクリプトはOVRCameraRigにアタッチしておきます。

```C#:ControllerOperate.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ControllerOperate : MonoBehaviour {
    private const float cameraHeight = 0.8f;
    private const float cameraDistance = 1.5f;
    private GameObject testCamera;
    private Vector3[] cameraPositions = {
            new Vector3(0f, cameraHeight, cameraDistance),
            new Vector3(cameraDistance, cameraHeight, 0f),
            new Vector3(0f, cameraHeight, -cameraDistance),
            new Vector3(-cameraDistance, cameraHeight, 0f),};
    private int direction = 0;
    void Start()
    {
        testCamera = GameObject.Find("Test Camera");
        testCamera.transform.position = cameraPositions[0];
        testCamera.transform.rotation = new Quaternion(0, 0, 0, 0);
        testCamera.transform.Rotate(new Vector3(0, 1, 0), 180);
    }
    void Update()
    {
        if (OVRInput.GetDown(OVRInput.RawButton.A))
        {
            direction = direction == 3 ? 0 : direction + 1;
            testCamera.transform.position = cameraPositions[direction];
            testCamera.transform.Rotate(new Vector3(0, 1, 0), 90);
        }
    }
}
```

![016.png](https://qiita-image-store.s3.amazonaws.com/0/187536/bf04de8f-23f7-c4e0-38ca-bc3d913d78ce.png)

#微調整

ここからは、ヘッドセットを被って微調整です。

**・普通に立ってるのに、かかとを立てて背伸びになってしまう。**
→モデルと自分の背丈があわないためと思われます。HeadObjectを少し下げて調整。
![017.png](https://qiita-image-store.s3.amazonaws.com/0/187536/e2bf931d-3204-a962-0589-5cd8eead213c.png)

**・足が開き過ぎ。女の子らしくない。**
→VRIKのパラメータで調整します。なお、調整中に歩行できなくなってきたので、参考にさせて頂いた記事のように、かかとにCubeを置いて追随させるようにしてみました。なお、このままでは歩行が瞬間移動みたいになってしまうのですが、今回は保留としました。
![22.png](https://qiita-image-store.s3.amazonaws.com/0/187536/01263ad7-e5f1-fa3b-8427-862aaac5ff7a.png)
![23.png](https://qiita-image-store.s3.amazonaws.com/0/187536/aab18c51-492e-8f67-8436-613b4ec65753.png)
![24.png](https://qiita-image-store.s3.amazonaws.com/0/187536/98a2b039-a13d-97b8-a729-1046b63d964b.png)
![26.png](https://qiita-image-store.s3.amazonaws.com/0/187536/7030b521-1be4-e138-1056-a95187433040.png)


**・顔の構成物が見えてしまって、怖い。**
→下記方法で、モデルのVRM First Personスクリプトを有効にします。
1. VRM First Personのスクリプトソースを表示してFirstPerson、ThirdPerson用レイアの設定値を確認します。
2. SceneのLayersをEditして先程の設定値の対象レイアに割当ます。
3. VRM First PersonのSetupメソッドをstart時に実行するスクリプトを作成して、モデルにアタッチします。
4. メインのカメラと、視点上CeterEyeAnchorのカメラの、Culling Maskを設定して、レイア表示を変更します。
なお、モデルのインサイドちゃんは、VRM First Personスクリプトの各レンダー表示設定を、初期状態から変更していませんが、モデルによっては変更が必要かもしれません。

```C#:VRMFirstPerson.cs
namespace VRM
{
    public class VRMFirstPerson : MonoBehaviour
    {
        public const int FIRSTPERSON_ONLY_LAYER = 9;	//この数値を確認
        public const int THIRDPERSON_ONLY_LAYER = 10;	//この数値を確認
......
```

![019.png](https://qiita-image-store.s3.amazonaws.com/0/187536/179247da-0bc1-748b-ddd3-791ebe3ec790.png)

```C#:VRMFirstPersonSetting.cs
using UnityEngine;
using VRM;
public class VRMFirstPersonSetting : MonoBehaviour {
    private VRMFirstPerson vrmFPerson;
    void Start () {
        vrmFPerson = GetComponent<VRMFirstPerson>();
        vrmFPerson.Setup(); 
    }
}
```
![018.png](https://qiita-image-store.s3.amazonaws.com/0/187536/3925d17d-a966-c752-8c35-2433195b47bb.png)
![020.png](https://qiita-image-store.s3.amazonaws.com/0/187536/653ecdf2-0b28-7e01-6d07-7c1a8100cb89.png)
![021.png](https://qiita-image-store.s3.amazonaws.com/0/187536/f8959caa-9443-5f83-f3b3-2c4a9a1cdae2.png)

**・モデルの影がない。**
モデルのシェーダを確認すると、VRM/UnlitTextureとなっており、影を生成しない標準のUnlitと同じもののようです。VRMに元から入っているMtoonシェーダーに変更してみましたが、そのままだとモデルのイメージが大分変わってしまうので、今回は保留にしました。

#最後に

とりあえず動かせるようにはなりましたが、調整が大変でした。(ヘッドセットのディスプレイ部分だけ外してトラッカーだけにできたりしたら調整楽なんですが、いちいち被るの面倒くさい...VR表示内でキーボードは使えないし...)
次以降はシェーダの調整、指の動作、表情変更、カメラ移動の強化等に挑戦していく予定です。
なお、参考にさせていただいた記事を書いてくださった方、モデルを公開してくださったインサイドちゃん、ありがとうございました。

(ヘッドセットから画像のスクリーンショット)
![Test01.png](https://qiita-image-store.s3.amazonaws.com/0/187536/0a8fc496-d6cd-3c17-3986-96e4aad82cbb.png)
![Test02.png](https://qiita-image-store.s3.amazonaws.com/0/187536/b1561879-d88a-d75b-ea8d-cd7b97461aec.png)