Oculus Quest 2でMRTK使って豆腐と戯れる最小手順

# Oculus Quest にも対応したMixed Reality Toolkit V2.5.0を試したい
Ocuus Quest 2が手元に届いたので、さっそく何かを作ってみるチャレンジということで先日リリースされたMixed Reality Toolkit V2.5.0でアプリを作ってみました。最小手順で豆腐(Cube)をMRTKの機能で遊ぶコンテンツを作ってみます。
ただCubeを振り回して、ボタンを押すと初期位置に戻ってくるアプリになります。どちらかというを最小限でコンテンツ開発に必要な設定を備忘録として残すために作りました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">とりあえず、Oculus Quest 2が来たので <a href="https://twitter.com/hashtag/MRTK?src=hash&amp;ref_src=twsrc%5Etfw">#MRTK</a> 動かしてみる。V2.5.0でハンドトラッキングできるのを確認。<a href="https://twitter.com/hashtag/OculusQuest2?src=hash&amp;ref_src=twsrc%5Etfw">#OculusQuest2</a> <a href="https://t.co/mwHUZt8rIe">pic.twitter.com/mwHUZt8rIe</a></p>&mdash; takabrz1@MRTKV2とAzure Spatial Anchorsと格闘中 (@takabrz1) <a href="https://twitter.com/takabrz1/status/1316753021729075201?ref_src=twsrc%5Etfw">October 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



## 開発環境
今回の開発環境は以下の通りです。

* Windows 10 1909
* Unity 2019.4.10f1
* Mixed Reality Toolkit v2.5.0

### Oculus Questでの開発準備（Editorの環境)

最初に、Editor環境を整えます。
OculusはAndroidアプリとして構築するので、モジュールとして[Android Build Support]を追加します。
また、その配下の[Android SDK & NDK Tools]、[OpenJDK]をチェックしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/d487d9f3-6786-0ed8-b725-e2649cd9208c.png)

セットアップが完了したらUnity Editorを起動します。起動後[Preferences]-[External Tools]を選択し、Android関連のパラメータが設定されていることを確認します。上記の情報でモジュール追加していると自動で入ります。個別で設定している場合は正しくパスを通してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/08285c81-66f4-fa1a-2314-da7b58f070fb.png)

次にOculus Questで開発するための準備を進めていきます。手順そのものは以下のMRTKのドキュメントに従ってすると大丈夫です。

[How to configure Oculus Quest in MRTK using the XRSDK pipeline](https://microsoft.github.io/MixedRealityToolkit-Unity/version/releases/2.5.0/Documentation/CrossPlatform/OculusQuestMRTK.html)

### 必要なパッケージの追加とMRTKの導入

Ocuus Questに必要なパッケージとMRTKを導入します。
MRTKの導入にはunitypackageファイルでインポートするか、Unity Package Manager経由でインストールする2つの方法があります。
今回はUnity Package Manager経由で実施します。
作成したUnityプロジェクトをエクスプローラーで開き[プロジェクトパス]/Packages/manifest.jsonを開き、以下の内容を追記します。
[scopedRegistries]にMRTKのレジストリを登録し、dependenciesにMRTKに必要なパッケージ情報を記載します。
保存すると自動的に再読み込みが実行され、MRTKに必要なパッケージが自動的にセットアップされます。


```xml:manifest.json 
{
  "scopedRegistries": [
    {
      "name": "Microsoft Mixed Reality",
      "url": "https://pkgs.dev.azure.com/aipmr/MixedReality-Unity-Packages/_packaging/Unity-packages/npm/registry/",
      "scopes": [
        "com.microsoft.mixedreality",
        "com.microsoft.spatialaudio"
      ]
    }
  ],
  "dependencies": {
    "com.microsoft.mixedreality.toolkit.examples": "2.5.0",
    "com.microsoft.mixedreality.toolkit.foundation": "2.5.0",
    "com.microsoft.mixedreality.toolkit.tools": "2.5.0",
```

次に[Oculus XR Plugin]ををインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/23940857-244a-004f-903b-e0e59e4b1bfe.png)

以上で必要なパッケージの導入は完了です。

### プロジェクトの設定

次にUnityプロジェクトの設定を変更します。
[File]-[Build Settings]を選択しBuild設定を開き、[Platform]で[Android]にSwitch Platformします。
合わせて、開いているシーンを追加しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/119822bb-1862-102a-1b34-1b55071976cc.png)

プラットフォームを変更すると以下のようなMRTKのダイアログが表示される場合があります。[Apply]をおして必要な設定を行ってください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/3e5c5614-068c-db50-f81a-c2f82cef6ac2.png)


次に[Edit]-[Project Settings]を選択しプロジェクト設定を開きます。サイドメニューから[XR Plug-in Management]を選択し、[Plug-in Providers]の中からOculusをチェックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/229c8611-6e3b-fc3f-7b44-cb22dcafb5ec.png)

次にハンドトラッキングの設定を行います。
まずAsset Storeから[Oculus Integration]をインポートします。最新が20.1です。今回はMRTKのドキュメントでは20.0を使っていたので、[アーカイブ](https://developer.oculus.com/downloads/package/unity-integration-archive/20.0/)から取得しました。
インポート後にAsset/oculus/OculusProjectConfigを開きます。設定の中にある[Hand Tracking Support]を[Controllers And Hands]または[Hands Only]に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/0fc04cb0-3f78-0df2-4231-df160e58499b.png)

次にMRTKの設定を行います。[Mixed Reality Toolkit]-[Utilities]-[Oculus]-[Integrate Oculus Integration Unity Modules]を選択し導入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/64600c9e-f6d9-6672-fcb8-f36542799972.png)


### シーンにMRTKの設定を追加する

次にOcuus QuestでMRTKを使うための設定を行います。メニューから[Mixed Reality Toolkit]-[Add to Scene And Configure...]を選択し、シーンにMRTKに必要なコンポーネントの設定を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/defeb546-029e-90ea-d0a6-5b8b5f595edd.png)

### ハンドトラッキングの設定

次のハンドトラッキングを有効化する設定を行います。
[Hierarchy]内の[MixedRealityToolkit]を選択します。[Inspector]を開くと以下のようにコンポーネントが表示されます。設定変更するためにはプロファイルを作成する必要があるので[Copy & Customize]を押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/f93d78ee-003d-b17a-6228-8e1dda016d89.png)

[Clone Profile]ダイアログが表示されるので、[Profile Name]を任意に変更して[Clone]を押下してコピーを作ります。
作成後、Profile名が作成したものになっていることを確認してください。回っていないようであればプルダウンから選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/e8f17c10-617e-2c3e-0e08-c48e4cecc7c3.png)

次にサブメニューの[Input]を選択します。ここでもProfileの変更が必要ですので、[Clone]ボタンを押して先ほどと同じ要領でコピーを作成してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/ebd1aee3-e6e9-e63b-78cb-3b5c4511c2ac.png)

最後に[Input Data Provider]を展開し、[Add Data Provider]を押下します。最下行に[New data provider XX]が追加されるので、▼を押して展開し、Typeに[Microsoft.MixedRealityToolkit.XRSDK.Oculus.Input]-[OculusXRSDKDeviceManager]を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/c2d98044-be96-cbb8-c876-255214b4fa41.png)

最後に[Device Manager Profile]に[OculusXRSDKDeviceManagerProfile]を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/8f2cb6fe-98d0-cf5b-a5e5-3411c5f17637.png)

以上でOculusのハンドトラッキングで開発するのに必要な準備が完了しました。
次以降は実際に動くコンテンツを作成します。

### 豆腐を触れるコンテンツを作る

次にManipulation操作でCubeを操作する簡単なアプリを構築しましょう。以下の手順に従って設定を進めてきます。

1.空のGameObjectを作成し[Root]に名前を設定する。
2.[Asset]フォルダの下に[Scripts]フォルダを作成します。
3.[Scripts]フォルダの下に以下のC# Scriptを追加します。

```cs:
// Copyright (c) 2020 Takahiro Miyaura
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php

using UnityEngine;

public class AdjustXR : MonoBehaviour
{
    [SerializeField]
    private Vector3 vrOffset;

    [SerializeField]
    private Vector3 otherOffset;

    // Start is called before the first frame update
    private void Start()
    {
        
#if UNITY_ANDROID
        transform.position = vrOffset;
#else
        transform.position = otherOffset;
#endif

#if UNITY_ANDROID
        var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
        plane.transform.position = Vector3.zero;

#endif
    }
}
```

4.[AdjustXR]をドラッグ&ドロップで[Root]のコンポーネントとして追加します。
5.[Hierarchy]内の[Root]オブジェクトを選択し、[Inspector]内の[AdjustXR]のvrOffsetを(0,1,0)に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/371e979b-c8a9-aae2-3dcd-ce96ced195a7.png)

5.[Root]の子要素として[Cude]を生成し、positionを(0,0,1)、Rotationを(0,0,0)、Scaleを(0.2,0.2,0.2)に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/d8ed02e2-2d6d-5d74-6efa-6013bf880d43.png)

6.[Cube]に[Rigidbody]を追加し[useGravity]をFalse,[IsKinematics]をFalseに設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/a3eb2bea-f7af-9129-b886-df37dae72aba.png)

7.[Cube]に[Object Manipulator]を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/3b3ad315-dbf6-602d-57ea-56ca40eef241.png)

8.[Cube]に[NearInteractionGrabble]を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/246aeb8b-543c-d0f5-6398-0a53d4b6da7e.png)


9.[Scripts]フォルダの下に以下のC# Scriptを追加します。

```cs:ResetPosition.cs
// Copyright (c) 2020 Takahiro Miyaura
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php

using UnityEngine;

public class ResetPosition : MonoBehaviour
{
    private Vector3 position;

    private Rigidbody rigidbody;
    private Quaternion rotation;

    // Start is called before the first frame update
    private void Start()
    {
        position = transform.position;
        rotation = transform.rotation;

        rigidbody = GetComponent<Rigidbody>();
    }

    public void Reset()
    {
        rigidbody.useGravity = false;
        rigidbody.velocity = Vector3.zero;
        rigidbody.angularVelocity = Vector3.zero;
        transform.position = position;
        transform.rotation = rotation;
    }
}
```

10.[ResetPosition]をドラッグ&ドロップで[Cube]のコンポーネントとして追加します。
11.メニューから[Mixed Reality Toolkit]-[Toolbox]を開き、[HoloLens 2 Button 32x32mm]を押下してボタンを1つ追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/6b2dd9c8-6355-8a74-7e85-1faa1688fbc0.png)

12.追加したボタンを[Root]の子要素に変更します。
13.[Hierarchy]でボタンを選択し、positionを(0.2,0,0.5)、Rotationを(0,0,0)、Scaleを(2,2,2)に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/58b68033-ec9d-478a-765b-e9b1571fa4da.png)

14.ボタンに設定されている[Button Config Helper]を以下の通り設定します。

 * Enable Main Lavelをチェック
 * Main Lavel Textに[Reset]を設定
 * Onclickイベントのオブジェクトに[Cube]を設定し、呼出す処理に[ResetPosition.Reset]を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/f3d4224e-0bb7-3d2e-7730-55510a671f62.png)

以上で実装は完了です。今回利用したMRTKの機能は以下になります。

* Object Manipulator<br>対象のオブジェクトをハンドトラッキング or モーションコントローラーで操作（移動/サイズ/向きの変更）可能にします。
* NearInteractionGrablle<br>Object Manipulatorと組合わせて実行します。対象のオブジェクトを掴んで操作することが可能になります。
* HoloLens 2 Button 32x32mm<br>ハンドトラッキングで直接押すことができるボタンです。音声による操作やモーションコントローラーの操作にも対応しています。

### おまけ

HoloLens 2で実行する場合は、ProfileをHoloLens 2用に変更してデプロイすることでそのまま動く形になっています。空間マッピングの機能をOnにしておくとCubeが床面で反発したりすることも体験できます。

## まとめ

Oculus Quest 2が手に入ったのでまずは簡単にMixed Reality Toolkit で動作確認をしました。MRTKを活用すると大きな変更なしに複数のxRデバイスへの対応が容易に実現するのでぜひ活用してみてください。