【XR Kaigi 2023解説用】MRTK3 を使ったコンテンツ（空間操作/ハンドメニュー）を作成する（共通）

# クロスプラットフォームライブラリ「Mixed Reality Toolkit 3」を使ってみよう

この記事は、XR Kaigi 2023で登壇した「Mixed Reality Toolkit 3 で始めるクロスプラットフォーム開発」の中で解説した実装に関する記事です。
<iframe width="560" height="315" src="https://www.youtube.com/embed/xHpYMK9HWuE?si=g6XxUE1b0Q3klbbQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

2023年9月にリリースされた「Mixed Reailty Tookit 3」の環境構築とUX部品を使ってみたいと思った人向けに作成しました。MRTK3の概要については XR Kaigi内のセッションでも紹介していますが、関連ドキュメントなど詳細は以前記事にしたものがあるので合わせて参考にしてください。

https://qiita.com/miyaura/items/a36d89a8e708d1bcd722

本記事に関連する記事は複数あります。

https://qiita.com/miyaura/private/c8443173e05056ee3041

https://qiita.com/miyaura/private/be7e1ad2450d7aeff072

https://qiita.com/miyaura/private/093d0ae3ca9f6755723e

https://qiita.com/miyaura/private/50e017d9feb0d5b23d88

上記記事は本記事で作成した基本的なMRTK3を各デバイス向けの機能を利用して拡張し、各デバイス向けにビルドをする手順を整理したものになります。
まずは、この手順を参考にMRTK3での開発についての基本的な理解を進めた後に各デバイス毎の機能や設定を行うことでMRTK3をうまく活用することによる開発の効率化などを体験してもらうことが可能だと思います。

## 開発環境について
開発環境として必要なものは最低限Unityとなります。また、MRTK3を導入するために利用できるMixed Reality Feature Toolと呼ばれるパッケージ導入用のツールも利用します。

Unityのバージョンについてはデバイスによってはサポートバージョンが異なる場合があります。
本記事では以下の通り使い分けを行っています。

* Meta Quest 3向け　→　Unity 2022.3.7f1
* HoloLens 2, ThinkReality A3, VRX向け　→　Unity2021.3f22

今回の手順ではMeta Quest 3の機能を利用するために「Meta XR SDK(V59)」を利用しています。最新のバージョンはUnity 2021では動作しないためQuest 3のみバージョンを変えています。

本記事で利用する環境として撮っているスクリーンショットは以下のバージョンですが、Unity 2021.3系でも操作方法に大きな違いはありません。デプロイしたいデバイスに合わせて選択してください。

* ツール
   * Unity 2022.3.7f1
   * Mixed Reality Feature Tool
* 導入するライブラリ（インポート時に自動導入される依存ライブラリは未記載）
   * MRTK Input 3.0.0
   * MRTK Spatial Manipulation 3.0.0
   * MRTK Standard Assets 3.0.0
   * MRTK UX Components 3.1.0
   * MRTK UX Core Scripts 3.1.0
   * MRTK Graphics Tools 0.5.12
   * MRTK Core Definitions 3.0.0
   * Mixed Reality OpenXR Plugin 1.9.0

## 作成するアプリについて

今回はMRTK3の基本的な利用方法を紹介することを目的に最小限の機能とUX部品利用しています。機能としては以下のものになります。

* 基本機能<BR>MRTK3で提供されているカメラやコントローラなどの基本的設定
* Unity Play Modeでのハンドトラッキングシミュレータ<BR>Unity Editor上で動作確認する際に便利なキーボード操作でハンドトラッキングを行うための機能
* 3Dオブジェクトの空間操作(つかむ、移動/回転/サイズ変更)<BR>空間に存在する3Dオブジェクトを直感的に操作するための機能
* ハンドメニュー<BR>手元表示可能なメニューUI.ハンドトラッキングを利用できるデバイスでは手のひらを返すことで表示する事できます。（後述のSolverシステムを利用）![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/63e44d0a-2d2d-612f-4a86-1266833ea5f5.png)
* Solverシステム<BR>ハンドトラッキングや頭の動きなどを監視し「頭の向きに合わせて物体を追従」、「常に中央に固定」、「手のひらを返すとアクションが発生」といったあらかじめ定義された制約や機能に連携することができる仕組み

## 実装手順

本記事ではMRTK3の基本的な環境設定とサンプルとして動作するUI部品までの実装を行います。最後にUnity上で動作確認をするまでを実施します。各デバイスへのデプロイについては上記に上げている各デバイス向けの記事を参照してください。

1. Unityで空プロジェクトを作成
1. Mixed Reality Feature ToolでMRTK3を導入
1. MRTK3の設定(Project Settings
1. MRTK3のためのシーン設定
1. 3Dオブジェクト空間操作の設定
1. メニューの作成
1. Unity上で動作確認

### 1. Unityで空プロジェクトを作成

まずはUnityの空プロジェクトを作成します。Unity Hubを導入している場合は使用するUnityバージョンを指定し[3D]プロジェクトを作成してください。
次の工程に進む際に一度Unityを終了してください。次の手順ではMRTK3を導入するのですがパッケージの再読み込みのためにUnityの再起動する必要になります。

### 2. Mixed Reality Feature ToolでMRTK3を導入

次に[Mixed Reality Feature Toolをダウンロード](https://learn.microsoft.com/ja-jp/windows/mixed-reality/develop/unity/welcome-to-mr-feature-tool?WT.mc_id=WDIT-MVP-5003104)し展開、実行してください。
タイトルから次へ進むと以下のようにプロジェクトのパスを求められるので設定し[次へ]を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/02f93866-b727-c158-6000-8a7d7b6c7191.png)

するとUnityに導入可能なパッケージが表示されます。Mixed Reality Feature ToolはMRTK3以外にも様々なMixed Reality関連のパッケージを導入することが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/66fe6dbe-a845-7cf9-dd4c-effed4127b4d.png)

今回は以下の項目にチェックを行い[次へ]を押してください
* MRTK3
   * MRTK Input 3.0.0
   * MRTK Spatial Manipulation 3.0.0
   * MRTK Standard Assets 3.0.0
   * MRTK UX Components 3.1.0
   * MRTK UX Core Scripts 3.1.0
   * MRTK Graphics Tools 0.5.12
   * MRTK Core Definitions 3.0.0
* Platform Support
   * Mixed Reality OpenXR Plugin 1.9.0

Import Featuresでは選択したパッケージの依存関係を確認し不足しているパッケージを確認することができます。基本的には依存関係にあるパッケージが導入が必要ですのですべてがチェックされていることを確認して[次へ]を押します。
Review and ApproveではUnityのPackage.manifestの変更後の状態と、ローカルにダウンロードされるパッケージファイルのリストが表示されます。[Approve]を押して適用してください。なお、この時に古いManifestファイルはバックアップされます。何か問題があった場合はファイルを書き戻すことができます。

以上で、Unityの空プロジェクトにMRTK3関連のパッケージ導入が完了しました。次にUnity上でMRTK3の基本的な設定を行います。

### 3. MRTK3の設定(Project Settings)

Unityを起動するとすでにMRTK3が導入された状態になっているはずです。まずはMRTK3の設定から行います。本記事では最後にUnity上で動作確認をするのですがそのために必要なMRTK3の設定があります。
Unityの上部メニューから[Edit]-[Project Settings]を選択します。表示された[Project Settings]の項目から[MRTK3]を選択すると以下のような設定画面が表示されます。この設定はMRTK3で提供されるいくつかの機能を利用するためのプロファイル設定になっています。すべての機能を有効化した状態で利用します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/87090abc-912b-5deb-f75e-b57dd058d54b.png)
。今回はUnity Editor上で動作確認するため一番左の「Windows,mac,Linux settings」タブを選択し、[Assign MRTK Default]を押すことでプロファイルが設定されます。警告が表示されるかもしれませんが、今回は無視しても問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/2ef02531-c8c2-306e-73e4-f75fbde8b905.png)
次にMRTK3を使用するためのシーン設定を行います。
### 4. MRTK3のためのシーン設定
Unityを起動すると最初にSmapleSceneが開いていると思うのでこれを使って作りましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/41e056e8-4fd1-43cf-4cef-e93f6d7d0bef.png)

最初に[MRTK XR Rig]を導入します。このPrefabにはカメラやモーションコントローラ等の入力系の機能部品など含まれています。これをシーンに導入することでMRTK3の入力系の機能を利用することが可能になります。
[Project]パネルを選択し[MRTK XR Rig]を対象[In Packages]検索します。Prefabが表示されるので[Hierarchy]に追加してください。 **最後にHierarchy上位に入っている[Main Camera]を削除します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/a3179a0e-1c21-fae1-a189-af0178556b51.png)

次にUnity Editor上で動作確認するために必要な部品も導入します。これを導入するとPlay modeでキーボードによるハンドトラッキングのエミュレーションが可能になります。
先ほどと同じ要領で今度は[MRTK InputSimulator]を検索し見つかったPre![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/d1a98e1e-e3b1-9229-2fbd-cad6c2878554.png)
fabをhierarchyに追加します。

この状態でUnity EditorでPlay Modeを実行し、Shift or Spaceを押すと空間に手のゴーストが表示されハンドトラッキング動作を実施することが可能です。
シミュレーションのチートシートは[こちら](https://learn.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/mrtk3-input/packages/input/input-simulation?WT.mc_id=WDIT-MVP-5003104)のサイトに記載があるので参考にしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/8e5a6d3d-510e-9c78-b0b5-949f60ccb8aa.png)

### 5. 3Dオブジェクト空間操作の設定

次に空間に操作可能なオブジェクトを作成し、各デバイスで操作できることを確認してみましょう。
今回は最初に2つの物体を表示し両方とも操作（移動/回転/サイズ変更）可能とします。また、片方は操作後に重力落下するように実装します。これは各デバイスで空間認識などの機能を利用した際に空間との干渉を確認できるようにするためです。

まずは任意の物体を2つ作成します。作成する物体は何でもいいのですが今回は球体と立方体を作成しています。
それぞれ以下の通り空間に作成しています。

1. 球体
    * position (0.3,0.0,1.0)
    * rotation (0,0,0)
    * scale (0.2,0.2,0.2)
    * コンポーネント（追加）
        * Rigidbod
            * Use Gravityのチェックを外す
        * Object Manipulator
1. 立方体
    * position (-0.3,0.0,1.0)
    * rotation (0,0,0)
    * scale (0.2,0.2,0.2)
    * コンポーネント（追加）
        * Rigidbod
            * Use Gravityのチェックを外す
        * Object Manipulator
            * Maniputation Startedイベントに自身のRigidbody.UseGravityをオンにする設定を追加<BR>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/e9a5bd0e-4a17-de59-7c64-5b2e1b112dda.png)

Object ManipulatorというのがMRTK3で提供されているSpatial Manipulationの部品の１つです。この部品をColiderがついている3Dオブジェクトに追加すると、ハンドトラッキングでつかんだり、レイによる操作が可能になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4706dab8-1857-6b0c-e25a-e386b18474dd.png)
よく使うものとしては以下のパラメータになります。

* Allowed Manipulations<BR>オブジェクトに対して許可する操作。移動/回転/サイズ変更等を組合わせて設定可能![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/77c325f7-6b52-ac4e-7f89-4df412ce60a9.png)


* Allowed Interaction Type<BR>オブジェクトに対して許可する操作手段。ハンドトラッキングのみ操作できる等を設定可能<BR>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/06033579-3877-d3cf-efe9-ab6a449f2833.png)

* Manipulation Started<BR>オブジェクトの空間操作が開始される際に発生するイベント
* Manipulation Ended<BR>オブジェクトの空間操作が完了する際に発生するイベント

また、例えば水平回転のみ許可したいような場合に操作時に制約を加えることも可能です。

この時点でPlay Mode上で物体の操作が可能です。ぜひ操作してみてください。

### 6. メニューの作成

つぎにハンドメニューを導入しましょう。ハンドメニューは文字通り手元で利用可能なメニューを作成する際に便利なUX部品です。デフォルトではハンドトラッキングように作成されており、手のひらを返すと手に追従するメニューとして簡単に導入することが可能です。
今回はハンドメニューとして、「オブジェクトの位置をもとに戻す処理」、「アプリケーションの終了」を追加したいと思います。なお、関連記事では各デバイス固有機能をこのハンドメニューに追加しています。
[Project]パネル内の検索に「Menu Base」を入力して検索すると表示される[HandMenuBase]をHierarchyに追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/3db17de6-cb5b-2ba1-6fe8-eea618ce0ab8.png)

追加するとTextMeshProのリソースのインポートをするようにダイアログが表示される場合があります。これが表示された場合は[Import TMP Essentials]だけ押して設定を行ってください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/08fcb354-bd57-39d8-00d4-65e2fef19b99.png)

[Hierarchy]に追加後、HandMenuBaseのPrefabをUnpackして、メニューの変更を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/cf7c9eaa-fed1-4158-5e46-6830f4b985ea.png)

次に、HandMenuBaseを展開し、[Button-GridLayout]にある4つのボタンを2つに減らします。2つに減らすと自動的にそのサイズにあった調整がされるようになっています。これはUGUIの機能として提供されているものです。MRTK3ではこういった既存の機能をうまく利用してUIの構築などの労力を低減しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/6331f4f5-202e-7060-621a-084879f94457.png)


次にボタンの外観(アイコン)を変更します。アイコンの変更はAction Buttonの中にある部品で変更します。
先ほど展開した[Button-GridLayout]のアクションボタンに対して次の階層まで移動してください

* [Action Button]-[Frontplate]-[AnimationContent]-[Icon]-[UIButtonFontIcon]

このオブジェクトの[Inspector]パネルから[Front Icon Selector]コンポーネントを探します。このコンポーネント内で好みのアイコンを選択していきます。今回は以下の設定をしました。

* Icon 3 → オブジェクトの位置リセット
* Icon 124 → アプリケーションの終了

このメニューで動作するロジックを作成します。Assets内の任意の場所にC#スクリプトを以下のように実装してください。

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

using UnityEngine;

public class MenuScripts : MonoBehaviour
{
    public Rigidbody[] ResetObjects;

    private Vector3[] _initialPositions;

    // Start is called before the first frame update
    private void Start() {
        _initialPositions = new Vector3[ResetObjects.Length];
        for (int i = 0; i < ResetObjects.Length; i++) {
            _initialPositions[i] = ResetObjects[i].position;
        }
    }

    public void Reset() {
        for (int i = 0; i < ResetObjects.Length; i++) {
            ResetObjects[i].useGravity = false;
            ResetObjects[i].velocity = Vector3.zero;
            ResetObjects[i].position
                = Camera.main.transform.position + Camera.main.transform.rotation*_initialPositions[i];
        }
    }

    public void ApplicationExit() {
        Application.Quit();
    }
}

```

実装したコンポーネントはHandMenuBaseに追加します。合わせてコンポーネントを以下のように設定してください。操作するオブジェクトの位置をリセットするために、MenuScriptsのパラメータにこのオブジェクトを渡しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/e7fcc85b-c632-9443-a705-a96d5a6c31c7.png)

最後に、HandMenuBaseのなかにあるAction ButtonのonClickイベントにMenuScriptsのResetメソッドと、ApplicationExitメソッドを割り当てて完了です。


### 7. Unity上で動作確認

この状態でアプリをUnity Editorで実行すると以下のことが確認できます。

* ハンドレイ、または直接つかむことでオブジェクトの移動/回転/サイズ変更が可能
* 立方体は操作後に自由落下
* 手のひらを返す動作によりハンドメニューが表示
* Resetボタンを押すことで3Dオブジェクトは初期位置に戻る

以上で共通の実装は終わりです。このようにUIやUXに関連する部分をMRTK3で構築することが可能です。他にも作るのが面倒なUX部品や処理といったものがプリセットで部品化されておりコンテンツ開発の効率化を実現することができます。このプロジェクトをベースに各デバイスの機能を組合わせて実機にデプロイする部分に関しては以下を参照してください。

* [【XR Kaigi 2023解説用】MRTK3と空間マッピング を使ったコンテンツ作成（HoloLens 2向け）](https://qiita.com/miyaura/private/c8443173e05056ee3041)
* [【XR Kaigi 2023解説用】MRTK3と空間マッピング, Dual Render Fusionを使ったコンテンツ作成（ Lenovo ThinkReality A3向け）](https://qiita.com/miyaura/private/be7e1ad2450d7aeff072)
* [【XR Kaigi 2023解説用】MRTK3とpassthrough, 空間マッピングを使ったコンテンツ作成（ Lenovo VRX向け）](https://qiita.com/miyaura/private/093d0ae3ca9f6755723e)
* [【XR Kaigi 2023解説用】 MRTK3とpassthrough, scene を使ったコンテンツ作成（Meta Quest 3向け）](https://qiita.com/miyaura/private/50e017d9feb0d5b23d88)