クロスプラットフォームライブラリ「Mixed Reality Toolkit 3」を使ってみよう
この記事は、XR Kaigi 2023で登壇した「Mixed Reality Toolkit 3 で始めるクロスプラットフォーム開発」の中で解説した実装に関する記事です。
この記事は、2023年9月にリリースされた「Mixed Reailty Tookit 3」の環境構築とUX部品を使ってみたいと思った人向けに作成しました。本記事はMRTK3で構築したコンテンツに対して以下の作業を実施する手順を記載しています。
- passthrough機能の設定
- sceneの設定
- モーションコントローラ時のHandMenu対応
- Meta Quest 3にデプロイ
本記事の手順は事前に以下の記事でUnityプロジェクトを作成済みの状態からスタートすることを前提にしていますが、作業手順自体は汎用的なものなので必要に応じて活用してください。
MRTK3の概要については XR Kaigi内のセッションでも紹介していますが、関連ドキュメントなど詳細は以前に記事にしたものがあるので合わせて参考にしてください。
本記事に関連する記事は複数あります。
Meta Quest 3以外のデバイスでのMRTK3を使うことに興味がある方は参考にしてください。
開発環境について
Meta Quest 3にデプロイするために必要なツールとライブラリは以下の通りです。
- ツール
- Unity 2022.3.7f1
- Android Build Support
- Open JDK
- Android SDK & NDK Tools
- Android Build Support
- Mixed Reality Feature Tool
- Unity 2022.3.7f1
- 導入するライブラリ(インポート時に自動導入される依存ライブラリは未記載)
- 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
- Mixed Reality OpenXR Plugin 1.9.0
- Meta XR SDK v59.0
- Meta XR Core SDK 59.0.0
- Meta XR Interaction SDK 59.0.0
- Meta XR Interaction SDK OVR Integration 59.0.0
- MRTK3関連
プロジェクトを作成する
MRTK3でのアプリ実装については以下の記事を参照してUI部分の構築を行ってください。以降はこの手順で作成したプロジェクトを変更しながら機能を追加していきます。
なお、上記記事はUnity 2021.3系で作成しています。Meta Quest 3用にプロジェクトをUnity 2022.3系に変更する必要があります。
Meta XR SDKの導入について
Meta XR SDKはAsset Store経由でインポートすることが可能です。
以下のコンポーネントをPackage Managerを使ってインポートします。
- Meta XR Core SDK 59.0.0
- Meta XR Interaction SDK 59.0.0
- Meta XR Interaction SDK OVR Integration 59.0.0
導入後[Edit]-[Project Settings]を開き、Checklistで必要な設定を行います。
なお、今回はMRTK3を利用する関係で最終的には以下のようにいくつかエラーが残るようになります。
MRTK3とMeta XR SDKの併用について
MRTK3のみでMeta Quest 3用のアプリ作成する場合は特に問題はないのですが、Meta XR SDKと組み合わせる場合、現状少し無理矢理な導入の仕方になります。デプロイしてしまえば問題ないのですが、Unity EditorでPlay Modeを実行する際などに以下のようなダイアログが表示されます。表示された場合はCancelを押してください。
このダイアログはMeta XR SDKのパッケージをインポートしている&XR Plug-in ManagementでOpenXRの設定を有効にしている場合に発生するようです。Meta Quest 3でMRTK3を利用したい場合、現状ハンドトラッキングやモーションコントローラを利用するためにはMicrosoft Mixed Reality OpenXR Pluginを利用する必要があります。このプラグインとMeta XR SDKの競合するようです。
passthrough機能の設定
Meta Quest 3でPassthrough機能を利用するために今回はMeta XR SDKを利用します。シーンに必要なコンポーネントを追加して実装します。今回はMeta Quest 3のパススルー切替えをメニューから行えるように切替える実装も行っています。パススルーの切り替えはCameraの背景カラーを透過/不透過に切替えることで実現することが可能です。
- [MRTK XR Rig]-[Camera Offset]-[Main Camera]を選択し、[Camera Setting Manager]の以下の設定を変更する
- 任意場所に空のGameObjectを追加
- 追加したオブジェクト名をPassthroughに変更(任意)
- PassthroughのInspectorパネルから以下のコンポーネントを追加/設定する
- [OVR Manager]を追加し以下のパラメータを設定
- Target Devicesの[Quest 3]をチェック
- Enable Passsthroughをチェック
- [OVR Passthrough Layer]を追加
- PlacementをUnderlayに変更
- [PassthroughToggleSwitchForQuest3]を追加(コードは後述)
- パラメータのPassthrough Layerは自分自身を設定する
- [OVR Manager]を追加し以下のパラメータを設定
// Copyright (c) 2023 Takahiro Miyaura
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
using UnityEngine;
public class PassthroughToggleSwitchForQuest3 : MonoBehaviour{
public bool IsPassthroughOn{ get; private set; }
public OVRPassthroughLayer PassthroughLayer;
private Material _material;
// Start is called before the first frame update
private void Start() {
IsPassthroughOn = OVRManager.instance.isInsightPassthroughEnabled;
SetPassthrough(IsPassthroughOn);
_material = new Material(RenderSettings.skybox);
}
public void SetPassthrough(bool isPassthroughOn) {
PassthroughLayer.textureOpacity = isPassthroughOn ? 1.0f : 0.0f;
RenderSettings.skybox = isPassthroughOn ? null: _material;
Camera.main.backgroundColor = isPassthroughOn ? new Color(0,0,0,0) : Color.black;
}
}
次にアプリ内でメニューから変更できるようにHandMenuを改修します。
プロジェクト内に作成済みのHandMenuBaseを展開し[Buttons-GridLayout]の下に[CanvasButtonToggleSwitch]を追加します。[CanvasButtonToggleSwitch]はProjectパネルからパッケージ内を検索して追加することができます。これもMRTK3のUX部品の1つでボタンを押すごとにOn/Offが切り替わるボタンになります。これに合わせてイベントも発生するので、先ほどGameObjectに追加した[PassthroughToggleSwitch]のSetPassthroughメソッドでパススルーの有効無効化処理をOnToggled,OnUntggoledイベントに割り当てておきます。
Sceneの設定
今回はMeta Quest 3のシーンの機能も利用します。この機能を使うと実際の空間をスキャンして仮想的なルームを作成することができます。ルームには壁や床を構築することができます。
このルームに床や壁にColliderを入れることで疑似的に現実空間と干渉するようなコンテンツや、壁の一部が別世界になるといった演出を実現することができます。
この機能を利用するためには以下の手順を実施します。最初にルームの壁や境界となるオブジェクトをPrefabで作成しておきます。
[PlaneMesh]Prefabの作成
- 任意の場所に空オブジェクトを作成、名前を[PlaneMesh]に変更します。
- [PlaneMesh]に以下の設定を行いPrefab化します。Prefab化した後はシーンから削除します。
[Volume]Prefabの作成
- 任意の場所に空オブジェクトを作成、名前を[Volume]に変更します。
- [Volume]に以下の設定を行いPrefab化します。Prefab化した後はシーンから削除します。
- [OVR Scene Anchor]を追加
- [OVR Scene Plane Mesh Filter]を追加
- [Mesh Filter]を追加
- [Mesh Renderer]を追加。Mesh Rendererには[Meta XR Core SDK]内にあるPlaneマテリアルを設定
- 空の子GameObjectを追加し、名前を[Collider]に変更します。
- [Collider]に[Box Collider]を追加ます
- 空の子GameObjectを追加し、名前を[Mesh]に変更します。
- [Collider]に[Mesh Filter]を追加
- [Collider]に[Mesh Renderer]を追加。Mesh Rendererには[Meta XR Core SDK]内にあるPlaneマテリアルを設定Volumeマテリアルを設定
次にScene機能を利用するための設定を行っていきます。
- Hierarchyパネルから[passthrough]オブジェクトを選択しOVR Managerの以下の設定を変更します。
これでSceneを利用する設定は完了です。アプリケーションを起動した際にルームの設定がされていない場合は空間をスキャンしてルームを作る作業からスタートします。すでに設定済みの際は先ほど設定したPlaneMeshのマテリアルで空間に仮想的な部屋が可視化されます。
モーションコントローラを使う場合の対応
Meta Quest 3はハンドトラッキングと付属のモーションコントローラが利用可能です。モーションコントローラを利用したい場合、今回のアプリで提供しているHandMenuの機能は利用できません。このメニュー部品のUXはハンドトラッキング用に作成されているため「ハンドトラッキングで手のひらを返す時にメニューを表示する」ように作られています。今回はこのメニュをモーションコントローラのPrimaryButtonが押された時に表示/非表示するように実装します。MenuScriptを継承してMeta Quest 3用に拡張して実装します。
HandMenuの挙動を変更する部分はOnEnalbeメソッドで実装しています。アプリ実行中に入力デバイスの情報を検索しモーションコントローラを検出している場合は、HandMenuの挙動を変更しています。具体的には以下の実装を変更しています。
- HandMenuに実装されているSolverHandlerを変更
- メニューの追従は頭の動きに合わせる
- 手のひらで行うためのコンポーネントは無効化
- UGUIコンポーネントのRaycastTargetを有効にする(おまじない)
- 左右のモーションコントローラのPrimary Buttonが押された際にメニュー制御するイベントを設定
* PrimaryButtonが押されるたびにメニューの表示/非表示を実行
// Copyright (c) 2023 Takahiro Miyaura
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
using System.Collections.Generic;
using MixedReality.Toolkit;
using MixedReality.Toolkit.SpatialManipulation;
using MixedReality.Toolkit.UX;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using UnityEngine.XR;
using InputDevice = UnityEngine.XR.InputDevice;
public class MenuScriptsForQuest3 : MenuScripts{
private bool _isXRController;
private SolverHandler _solverHandler;
public GameObject HandMenuBase;
public InputActionReference LeftControllerPrimary;
public PassthroughToggleSwitchForQuest3 PassthroughFeature;
public PressableButton PassthroughToggle;
public InputActionReference RightControllerPrimary;
public TextMeshPro text;
public virtual void OnEnable() {
LeftControllerPrimary.action.performed += OnPrimaryButtonPressed;
RightControllerPrimary.action.performed += OnPrimaryButtonPressed;
var inputDevices = new List<InputDevice>();
InputDevices.GetDevices(inputDevices);
foreach (var inputDevice in inputDevices) {
_isXRController = inputDevice.name.Contains("Oculus");
}
if (_isXRController) {
HandMenuBase.GetComponent<HandBounds>().enabled = false;
HandMenuBase.GetComponent<HandConstraintPalmUp>().enabled = false;
_solverHandler = HandMenuBase.GetComponent<SolverHandler>();
_solverHandler.TrackedTargetType = TrackedObjectType.Head;
_solverHandler.UpdateSolvers = false;
var orbital = HandMenuBase.EnsureComponent<Orbital>();
orbital.LocalOffset = new Vector3(0, 0, 0.5f);
SetButtonRaycastTarget(true);
} else {
HandMenuBase.GetComponent<HandBounds>().enabled = true;
HandMenuBase.GetComponent<HandConstraintPalmUp>().enabled = true;
_solverHandler.TrackedTargetType = TrackedObjectType.HandJoint;
_solverHandler.UpdateSolvers = true;
SetButtonRaycastTarget(false);
}
}
private void SetButtonRaycastTarget(bool raycastTarget) {
foreach (var button in HandMenuBase.GetComponentsInChildren<PressableButton>(true)) {
button.transform.Find("Frontplate").GetComponent<RawImage>().raycastTarget = raycastTarget;
}
}
public virtual void OnDisable() {
LeftControllerPrimary.action.performed -= OnPrimaryButtonPressed;
RightControllerPrimary.action.performed -= OnPrimaryButtonPressed;
}
// Start is called before the first frame update
public override void Start() {
base.Start();
PassthroughToggle.ForceSetToggled(PassthroughFeature.IsPassthroughOn);
}
private void OnPrimaryButtonPressed(InputAction.CallbackContext ctx) {
if (!_isXRController) return;
var menu = HandMenuBase.transform.GetChild(0).gameObject;
menu.SetActive(!menu.activeSelf);
_solverHandler.UpdateSolvers = !_solverHandler.UpdateSolvers;
}
}
最後にコンポーネントの設定を行います。HandMenuBaseオブジェクトに設定していたMenuScriptコンポーネントを先ほど作成したMenuScriptsForMeta Quest 3に置き換えます。パラメータの設定は以下の図を参考に設定してください。
primaryButtonについてはXRIの仕組みを使用してアクションを取得しています。
以上で、passthroughと空間マッピングの実装が完了です。
Meta Quest 3へのデプロイ
Meta Quest 3にデプロイするために設定は次の通りです。Meta Quest 3はハンドトラッキングまたは、モーションコントローラを利用できるためそれぞれで一部設定が異なります。
- Build Settingsの変更
- AndroidManifest.xmlファイルの作成
- ハンドトラッキングを利用
- MRTK3の設定
- XR Plugin Management(Open XR) の設定
- モーションコントローラを利用
- MRTK3の設定
- XR Plugin Management(Open XR) の設定
- デプロイ
1. Build Settingsの変更
Unity Editorのメニューから[File]-[Build Settings]を選択しBuild Settingsパネルを表示します。Meta Quest 3向けのアプリはAndroidを選択する必要があるので、Platformから[Android]を選択し、[Switch Platform]を押下します。
2. AndroidManifest.xmlの作成
Meta Quest 3でハンドトラッキングやシーン、Passthroughを利用するための設定をAndroidManifestに記載します。
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="com.oculus.intent.category.VR" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
</activity>
<meta-data android:name="com.oculus.handtracking.frequency" android:value="LOW" />
<meta-data android:name="com.oculus.handtracking.version" android:value="V2.0" />
<meta-data android:name="com.oculus.supportedDevices" android:value="quest2|questpro|eureka" tools:replace="android:value" />
</application>
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
<uses-feature android:name="oculus.software.handtracking" android:required="false" />
<uses-permission android:name="com.oculus.permission.HAND_TRACKING" />
<uses-permission android:name="com.oculus.permission.USE_ANCHOR_API" />
<uses-feature android:name="com.oculus.feature.PASSTHROUGH" android:required="false" />
<uses-permission android:name="com.oculus.permission.USE_SCENE" />
</manifest>
3. ハンドトラッキングを利用
Meta Quest 3でMRTK3のハンドトラッキングを利用する場合の環境設定を行います。
3-1. MRTK3の設定
次にAndroid用のMRTK3の設定を行います。Unityのメニューから[Edit]-[Project Settings]を選択しプロジェクト設定パネルを表示します。
左のメニューから「MRTK3」を選択します。右側にMRTK3のプロファイル設定についての項目が表示されます。プラットフォームごとのタブが表示されているので「Androidアイコン」のタブが選択されていることを確認してMRTK3のプロファイルを設定してください。
プロファイル設定については今回はデフォルトの設定で特に問題がないためパッケージに入っているデフォルトの[MRTKProfile]を割り当てます。
3-2. XR Plugin Management(Open XR) の設定
次にMeta Quest 3用にXR系の設定を行っていきます。引続き[Project Settings]の中から[XR Plug-in Management]を選択します。プラットフォームごとのタブが表示されているので「Windowsアイコン」のタブが選択されていることを確認したうえで以下の項目にチェックが入れてください。
- Initialize XR on Startup
- OpenXR
- Meta XR feature group
上記の設定を行った後[Project Validation]の項目をチェックするといくつかの警告が表示されます。右上の[Fix All]を何回か押すことでSnapdragon Spaces向けにプロジェクトの設定が是正されます。
警告をすべて消すためにはいくつか手動パッケージの導入等必要になります。具体的にはデバイス毎のモーションコントローラのモデル表示関する設定です。また、現状MRTK3上でMeta Quest 3の入力系の機能を利用すするためにはMixed Reailty OpenXR Pluginを利用するのですがAndroid用のこの機能は互換性維持のために残されている機能のため警告が表示されます。今後は正式な対応手段が提供されると思います。
次に[OpenXR]で必要な設定を行います。[XR Plug-in Management]-[OpenXR]を選択します。以下の設定が行われているかを確認してください。
- Interaction Profileには何も設定しない
- OpenXR Feature Groupsの以下をチェック
- Meta XR
- Hand Tracking
- Motion Controller Model
4. モーションコントローラを利用
Meta Quest 3でMRTK3のハンドトラッキングを利用する場合の環境設定を行います。
4-1. MRTK3の設定
次にAndroid用のMRTK3の設定を行います。Unityのメニューから[Edit]-[Project Settings]を選択しプロジェクト設定パネルを表示します。
左のメニューから「MRTK3」を選択します。右側にMRTK3のプロファイル設定についての項目が表示されます。プラットフォームごとのタブが表示されているので「Androidアイコン」のタブが選択されていることを確認してMRTK3のプロファイルを設定してください。今回のサンプルではモーションコントローラを使わない場合MRTK3のサブシステムはすべて使用しません。このため、ProjectパネルからAssets配下の任意の場所に空のMRTKProfileを作成し割り当ててください。
4-2. XR Plugin Management(Open XR) の設定
次にMeta Quest 3用にXR系の設定を行っていきます。引続き[Project Settings]の中から[XR Plug-in Management]を選択します。プラットフォームごとのタブが表示されているので「Androidアイコン」のタブが選択されていることを確認したうえで以下の項目にチェックが入れてください。
- Initialize XR on Startup
- OpenXR
- Meta XR feature group
上記の設定を行った後[Project Validation]の項目をチェックするといくつかの警告が表示されます。右上の[Fix All]を何回か押すことでSnapdragon Spaces向けにプロジェクトの設定が是正されます。
警告をすべて消すためにはいくつか手動パッケージの導入等必要になります。具体的にはデバイス毎のモーションコントローラのモデル表示関する設定です。また、現状MRTK3上でMeta Quest 3の入力系の機能を利用すするためにはMixed Reailty OpenXR Pluginを利用するのですがAndroid用のこの機能は互換性維持のために残されている機能のため警告が表示されます。今後は正式な対応手段が提供されると思います。
次に[OpenXR]で必要な設定を行います。[XR Plug-in Management]-[OpenXR]を選択します。以下の設定が行われているかを確認してください。
- Interaction Profileに[Oculus Touch Controller Profile]を追加
- OpenXR Feature Groupsの以下をチェック
- Meta XR
- Motion Controller Model
4. デプロイ
UnityでビルドしたAPKファイルをUnity経由、Meta Quest Developer Hub等を利用して実機にデプロイすれが作業完了です。