MixedRealityToolkitドキュメントまとめ

# はじめに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8e671a36-a70a-c925-20df-d1c8fb321681.png)

この記事は[マイクロソフトのMRTKの記事](https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/)を上から順番に日本語にして羅列したものです。
すでに、[日本語記事](https://hololabinc.github.io/MixedRealityToolkit-Unity/Documentation.ja/WelcomeToMRTK.html)はあるのですが、網羅的に閲覧するために一つの記事としてまとめました。(2.5の内容だったためか2.7にバージョンアップした際にサポート終了しているようです)

この記事を書いている段階で、MRTKのバージョンは2.7.0です。

https://github.com/Microsoft/MixedRealityToolkit-Unity/releases


# Mixed Reality Toolkit とは
MRTK-Unityは、UnityでのクロスプラットフォームMRアプリ開発を加速するためのコンポーネントと機能を提供するマイクロソフト主導のプロジェクトです。以下はその機能の一部です。

- クロスプラットフォームの入力システムと、空間的なインタラクションやUIのためのビルディングブロックを提供。
- エディター内でのシミュレーションにより、変更をすぐに確認できるラピッドプロトタイピングを可能にします。
- 拡張可能なフレームワークとして動作し、開発者はコアコンポーネントを交換することができます。

幅広いプラットフォームに対応しています。

|Platform|Supported Devices|
|:----|:----|
|OpenXR (Unity 2020.2 or newer)|Microsoft HoloLens 2 <br> Windows Mixed Reality headsets|
|Windows Mixed Reality|Microsoft HoloLens <br> Microsoft HoloLens 2 <br> Windows Mixed Reality headsets|
|Oculus (Unity 2019.3 or newer)|Oculus Quest|
|OpenVR|Windows Mixed Reality headsets <br> HTC Vive <br> Oculus Rift|
|Ultraleap Hand Tracking|Ultraleap Leap Motion controller|
|Mobile|iOS and Android|


# MRTKの概要
MRTKやUnityでのMixed Reality開発が初めての方は、お使いのデバイスやエミュレータにMRTK Examples Hubのサンプル・アプリケーションをインストールしてご覧になることをお勧めします。

**MRTK Example hubアプリをダウンロードする**

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/running-examples-hub?view=mrtkunity-2021-01

**ツールのインストール**

Microsoft HoloLensやWindows Mixed Realityなどの没入型（VR）ヘッドセット用のアプリケーションを構築するために必要なツールを入手します。Windows Mixed Reality開発用の独立したSDKはなく、Windows 10 SDK付きのVisual Studioを使用します。

Mixed Realityデバイスをお持ちでない方は、HoloLensをインストールすることができます。HoloLensエミュレータをインストールすれば、HoloLensがなくても、Mixed Realityアプリケーションの一部の機能をテストすることができます。また、Windows Mixed Realityシミュレーターを使用して、没入型ヘッドセット用のMixed Realityアプリをテストすることもできます。

Mixed Realityアプリの作成を始めるための最も簡単な方法として、UnityまたはUnrealゲームエンジンのいずれかをインストールすることをお勧めします。ただし、カスタムエンジンを使用したい場合は、DirectXに対してビルドすることもできます。

Unityを使用している場合は、Mixed Reality Toolkit for Unityの入力シミュレーションを使用して、ハンドトラッキングやアイトラッキングの入力など、さまざまなタイプの入力インタラクションをテストすることができます。Unrealプロジェクトの場合は、UX Toolsプラグインを使用して、一般的な入力インタラクションやユーザーエクスペリエンス機能をテストできます。


> ヒント
> 
> このページをブックマークし、定期的にチェックすることで、Mixed Realityの開発に推奨される各ツールの最新バージョンを知ることができます。


**インストールチェックリスト**

|ツール |ノート|
|:--|:--|
|[Windows 10](https://www.microsoft.com/software-download/windows10)<br><br> 最新版のWindows 10をインストールして、PCのOSがmixed realityアプリケーションを構築するプラットフォームと一致するようにします。|**Windows 10のインストール**<br> 最新バージョンのWindows 10は、「設定」の「Windows Update」からインストールするか、左欄のリンクからインストールメディアを作成してインストールすることができます。 <br> Windows 10の各リリースで利用可能な最新のmixed reality機能については、現在のリリースノートを参照してください。PCの「設定」→「更新とセキュリティ」→「開発者向け」で開発者モードを有効にする。 <br> <br> **エンタープライズおよび企業で管理されているPCに関する注意事項** <br> お使いのPCが組織のIT部門によって管理されている場合は、アップデートのためにIT部門に連絡を取る必要があるかもしれません。 <br> <br>**Windowsの「N」バージョン** <br> Windows Mixed Reality（VR）ヘッドセットは、「N」バージョンのWindowsではサポートされていません。|
|[Visual Studio 2019（16.8以降）](https://visualstudio.microsoft.com/downloads/)<br><br>Windowsなどに対応したフル機能の統合開発環境（IDE）です。コードの作成、デバッグ、テスト、デプロイにVisual Studioを使用します。| Visual Studio 2019 のインストール <br> 以下のワークロードを必ずインストールしてください。<br><br>- Desktop development with C++<br> - Universal Windows Platform (UWP) development <br><br>UWP ワークロードの中で、HoloLens 向けの開発を行う場合は、以下のオプションコンポーネントを必ずチェックしてください。<br><br> - USBデバイス接続<br><br>USB デバイス接続に関する注意事項<br>インストール時に「IP over USB」にチェックを入れる必要がありますが、デフォルトではチェックされていません。これは、HoloLensとUSBで通信するために必要です。<br><br>Unityについての注意点<br>意図的に新しい（LTSではない）バージョンのUnityをインストールしようとしている場合を除き、Visual Studioインストールの一部としてUnityワークロードをインストールせず、代わりにUnity 2019 LTSストリームをインストールすることをお勧めします。<br><br>既知の問題<br>Visual Studio 2019バージョン16.0でのMixed Realityアプリのデバッグには、いくつかの既知の問題があります。必ずVisual Studio 2019バージョン16.8以上にアップデートしてください。|
|[Windows 10 SDK (10.0.18362.0)](https://developer.microsoft.com//windows/downloads/windows-10-sdk)<br><br>HoloLens 2でWindows 10アプリを構築するための最新のヘッダー、ライブラリ、メタデータ、およびツールを提供します。	|HoloLens 2のアプリを構築するには、Windows SDK（ビルド18362以降）をインストールする必要があります。<br><br>デスクトップのWindows Mixed RealityヘッドセットまたはHoloLens（第1世代）向けのアプリケーションのみを開発する場合は、Visual Studio 2017がインストールするWindows SDKを使用できます。|
|[HoloLens 2 Emulator (Windows Holographic, version 21H1 May 2021 Update) (Install link: 10.0.20346.1002)](https://go.microsoft.com/fwlink/?linkid=2162581)<br><br>[HoloLens（第1世代）Emulator（Install link: 10.0.17763.134](https://go.microsoft.com/fwlink/?linkid=2065980)<br><br>エミュレータを使用すると、物理的なHoloLensがなくても、HoloLensの仮想マシンイメージ上でアプリケーションを実行できます。|エミュレータを使い始めるための詳細については、「HoloLens エミュレータを使用する」を参照してください。<br><br>エミュレータのインストールを成功させるには、お使いのシステムがHyper-Vをサポートしている必要があります。詳細については、以下の「システム要件」を参照してください。<br><br>HoloLens（第1世代）エミュレータに関する注意事項<br>インストールを正常に完了するには、Visual Studio 2017が必要です。HoloLens（第1世代）エミュレータをVisual Studio 2019でインストールする場合は、VSテンプレートの選択を解除し、Visual Studio Marketplaceからインストールする必要があります。|

**好みのエンジンをインストールする**

Windows 10、Visual Studio、Windows 10 SDKの準備ができたところで、お好みのエンジンをインストールして設定しましょう。

エンジンの選択がまだ必要な場合は、「[Mixed Reality開発入門](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/development?tabs=unity#what-technology-path-are-you-interested-in)」をご覧ください。

※ここではUnityのみ記載しています。

**1. 推奨されているUnityのバージョンをダウンロードする**

現在、Mixed Realityの開発に推奨されているバージョンは「Unity 2019.4 LTS（Long Term Support）」です。Unityをインストールして管理するには、Unity Hubを利用するのが最適です。


> 注意
> 
> Unity 2020 LTSを使用している場合は、HoloLens 2の開発でMixed Realityのサポートが可能です。ただし、現在、いくつかの既知の問題があります。これは、今年の後半に推奨されるUnityバージョンになる予定です。


異なるUnityエンジンとXRプラグインのバージョンでどのようなMixed Realityサポートが利用できるかについては、Choosing a Unity version and XR pluginをご覧ください。

[Download unity Hub](https://unity3d.com/get-unity/download)

Unityをインストールする際には、「Platforms」で以下のコンポーネントを確認してください。

- Universal Windows Platform のビルドサポート
- Windowsビルドサポート(IL2CPP)

![unityins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6fffd6dd-f975-161d-c9b7-5f5fecb032da.png)


これらのオプションを使用せずにUnityをインストールした場合は、Unity Hubの「モジュールを加える」メニューから追加することができます。

![addmod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/162bc6ca-1e4e-a9cc-8755-ad9820893b4d.png)

**2. Mixed Reality Feature Toolのインストール**
Mixed Reality Feature Toolは、開発者の方がMixed Reality機能のパッケージを発見し、Unityプロジェクトに追加するための新しい方法です。

パッケージを名前やカテゴリーで検索したり、依存関係を確認したり、インポートする前にプロジェクトのマニフェストファイルへの変更案を確認したりすることができます。必要なパッケージを確認したら、Mixed Reality Featureツールが、ご希望のプロジェクトにダウンロードします。

Mixed Reality Toolkitのインポート

![mrtkimport.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fda7655f-4515-5f2f-f21f-bc8865eeffd0.png)

MRTK（Mixed Reality Toolkit）は、Mixed Realityアプリケーションのためのオープン・ソースでクロス・プラットフォームの開発キットです。

- インストールおよび使用方法の説明に従って、「Mixed Reality Toolkit Foundation」パッケージを選択してインストールしてください。

厳選されたHoloLensやVRの開発ジャーニーの中の、スタートアップセクションを完了することをお勧めします。すでにHoloLens用のUnity開発の旅を続けている場合は、以下に記載されている残りのセットアップ手順を終えて、HoloLens 2 Getting Startedのチュートリアルに進みます。


> 重要
> 
> インストール手順は、MRTKとUnityの最新の安定版の組み合わせ（MRTK 2.6.1およびUnity 2019.4 LTS）を対象としていることに注意してください。


> 注意
> 
> UnityのMRTKを使用したくない場合は、すべてのインタラクションとビヘイビアを自分でスクリプトする必要があります。


[Mixed Reality Toolkit-Unity (GitHub)](https://github.com/Microsoft/MixedRealityToolkit-Unity)


**その他のツール［オプション］**

- Mixed Reality Companion Kit（GitHub） - HoloLensや没入型（VR）ヘッドセット上では直接動作しないかもしれませんが、代わりにそれらと組み合わせて、Windows Mixed Realityをターゲットとした体験を構築するためのコードビットやコンポーネントです。
- Mixed Reality Toolkit - Common（GitHub） - 共有のスクリプトとコンポーネントのコレクション。
  
**3. Mixed Reality開発のためにPCをセットアップする**
Windows 10 SDKは、Windows 10オペレーティングシステム上で最適に動作します。このSDKは、Windows 8.1、Windows 8、Windows 7、Windows Server 2012、Windows Server 2008 R2にも対応しています。ただし、古いOSではすべてのツールがサポートされているわけではありません。

> 備考
> 
> アプリは、HoloLens、VR 没入型ヘッドセット、またはその両方向けに開発および展開できます。お客様のニーズに応じて、以下の要件を満たしていることを確認してください。


**HoloLens向けに開発する場合**
HoloLens開発用の開発PCをセットアップする際は、UnityとVisual Studioの両方のシステム要件を満たしていることを確認してください。アプリをHoloLensデバイスで実行する場合は、Windows Device Portalのセットアップ手順に従う必要があります。HoloLensエミュレータを使用する予定の場合は、お使いのPCがHoloLensエミュレータのシステム要件を満たしていることも確認してください。

HoloLensエミュレータを使い始めるには、「HoloLensエミュレータの使用」を参照してください。

HoloLensとWindows Mixed Realityの両方の没入型（VR）ヘッドセット向けの開発を予定している場合は、以下のセクションのシステム推奨条件と必要条件を使用してください。

**HoloLensのトラブルシューティング**

**開発者モードの設定がグレーアウトしている**

デバイスで開発者モードを有効にする問題に遭遇した場合、デバイスの所有者ではない可能性があります。マルチユーザーモードでは、最初にデバイスを使用した人がデバイスの所有者となり、それ以降のユーザーは開発者モードやその他の設定変更を有効にするために必要な権限を持っていません。ただし、オートパイロット環境では、最初のユーザーがデバイスの所有者ではない場合があるという例外があり、その詳細はHoloLensのセキュリティドキュメントに記載されています。

考えられる解決策は以下の通りです。
- デバイスの所有者が、他のユーザーや開発者にデバイスを渡す前に、開発者モードをオンにする。
- IT/MDM 管理者が、特定のデバイスまたは開発者デバイスグループに対して CSP ポリシー ApplicationManagement/AllowDeveloperUnlock を有効にすることを提案します。
    -このポリシーは、プロビジョニングパッケージまたはHoloLensデバイスのMDMによって設定できます。
- Advanced Recovery Companion（ARC）の使用


> 注記
> 
> デバイス管理の詳細については、HoloLens デバイス管理の概要を参照してください。


**USB経由でデプロイできません**
アプリケーションをUSB経由で直接展開できない場合は、上記のインストール要件をすべて満たしていることを確認し、ステップバイステップのチュートリアルに従ってください。

**没入型（VR）ヘッドセットの要件**

> 注記
> 
> 以下のガイドラインは、没入型（VR）ヘッドセット開発用PCの現在の最小および推奨スペックであり、定期的に更新されます。


> 注意
> 
> このガイドラインは、没入型 (VR) ヘッドセットのアプリやゲームの対象となるコンシューマ PC のスペックを示した、最小 PC ハードウェア互換性ガイドラインと混同しないでください。

没入型ヘッドセットを開発するPCにフルサイズのHDMIおよび/またはUSB 3.0ポートがない場合は、ヘッドセットを接続するためのアダプターが必要です。

また、ハイブリッドグラフィックスを搭載したノートPCなど、一部のハードウェア構成では問題が発生することがあります。


| |Minimum|Recommended|
|:----|:----|:----|
|Processor|Notebook: Intel Mobile Core i5 7th generation CPU, Dual-Core with Hyper Threading Desktop: Intel Desktop i5 6th generation CPU, Dual-Core with Hyper Threading OR AMD FX4350 4.2Ghz Quad-Core equivalent|Desktop: Intel Desktop i7 6th generation (6 Core) OR AMD Ryzen 5 1600 (6 Core, 12 threads)|
|GPU|Notebook: NVIDIA GTX 965M, AMD RX 460M (2GB) equivalent or greater DX12 capable GPU Desktop: NVIDIA GTX 960/1050, AMD Radeon RX 460 (2GB) equivalent or greater DX12 capable GPU|Desktop: NVIDIA GTX 980/1060, AMD Radeon RX 480 (2GB) equivalent or greater DX12 capable GPU|
|GPU driver WDDM version|WDDM 2.2 driver|
|Thermal Design Power|15W or greater|
|Graphics display ports|1x available graphics display port for headset (HDMI 1.4 or DisplayPort 1.2 for 60Hz headsets, HDMI 2.0 or DisplayPort 1.2 for 90Hz headsets)|
|Display resolution|Resolution: SVGA (800x600) or greater Bit depth: 32 bits of color per pixel|
|Memory|8 GB of RAM or greater|16 GB of RAM or greater|
|Storage|>10 GB additional free space|
|USB Ports|1x available USB port for headset (USB 3.0 Type-A) Note: USB must supply a minimum of 900mA|
|Bluetooth|Bluetooth 4.0 (for accessory connectivity)|

Unityを使ったMRTKの開発が初めての方には、Unity開発の道のりを紹介しています。

[Start your Unity for HoloLens journey](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/unity-development-overview)

[Start your Unity for VR joueney](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/unity-development-wmr-overview)

**次の開発チェックポイント**
Unity for HoloLensの開発チェックポイントに沿って開発を進めている場合、次の作業はHoloLens 2のチュートリアルシリーズに取り組むことになります。

[HoloLens2 tutorial series](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/tutorials/mr-learning-base-01)

Unity for VRの旅を続けている場合、次のタスクはプロジェクトをセットアップすることです。

[Configuring your project for WMR](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/configure-unity-project)

いつでも、HoloLensとVRのためのUnity開発チェックポイントに戻ることができます。

**HoloLens2 Tutorial Series**
https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/tutorials/mr-learning-base-02

**Explore MRTK on GitHub**
https://github.com/Microsoft/MixedRealityToolkit-Unity

# MRTK 2.7 リリースノート

2.7.0の新機能

**従来のXRとXR SDKのデータ・プロバイダを、同じプロファイル内で使用できるようになりました。**

データ・プロバイダーは、適切なパイプラインが選択された場合にのみロードされるようになり、Legacy XRとXR SDKのデータ・プロバイダーを同じプロファイル内で共存させることができるようになりました。これに対応するため、Legacy XRとXR SDKのデータ・プロバイダーは、プロファイル・ビューの中で異なるタブの下に整理され、ユーザーが対象となるXRパイプラインに対して正しいプロファイルを持っているかどうかを判断できるようになりました。

![legacyxr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/72fab436-5dbc-902b-3943-7171d332bf31.png)

これに対応するため、ヌルデータプロバイダは読み込まれず、プロファイルインスペクタに表示されなくなりました。ユーザーは、Edit -> Project Settings -> Mixed Reality Toolkit の「Show null data providers in the profile inspector（プロファイル・インスペクタにヌルデータ・プロバイダを表示する）」を切り替えて、データ・プロバイダがない場合の予期せぬ動作をデバッグすることができます。

![nulll.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/02641c2d-bfe9-3919-eeca-b9a6a17b16ef.png)



**エクスペリエンス設定と関連するMixed Reality Scene Contentビヘイビアの追加**

ユーザーがエクスペリエンス設定を設定できるようになりました。これにより、MRTKはターゲットとするエクスペリエンスに基づいてMixed Reality Scene Contentを適切に表示できるようになります。

ユーザーの以前のエクスペリエンス・スケール設定が新しいエクスペリエンス設定プロファイルと一致しない場合は、インスペクタで修正するよう促されます

![exset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4f61d2d7-f8bc-dbb6-691d-aa367d5b9807.png)

**再設計されたコンフィギュレータがセットアッププロセスをガイド**

新しいMRTKコンフィギュレータは、XRの開発とMRTKでの使用のためにプロジェクトを適切に構成するためのステップバイステップのガイダンスをユーザーに提供します。XRパイプラインの選択、プラットフォーム固有のプラグインの取得、TextMeshProのインポート、サンプルの表示（UPM使用時）など、これまでプロジェクトに含まれていた推奨設定をカバーしています。

![ccc.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/bc42f948-789c-d92c-373d-dc74ae32ebdc.png)

**段階的テレポートホットスポット**

新しいテレポートホットスポットコンポーネントが卒業しました。テレポートホットスポットをゲームオブジェクトに追加することで、ユーザーがその場所にテレポートしたときに特定の位置や方向にいることを確認できます。

![front.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1936c298-3fba-5edb-50b5-232e4dbdb040.png)


**卒業したDwell**
滞留機能とその例が実験的なものから卒業しました。ボリュメトリックなHoloLens 2スタイルのボタンの新しい例がサンプルシーンに含まれています。

![bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4e94b519-cef0-2de7-55d5-a222dc6f90af.png)

**Leap Motion Unity Modulesのバージョン4.6.0、4.7.0、4.7.1、4.8.0のサポートを追加しました。**

最新バージョンのLeap Motion Unity ModulesのサポートがMRTK 2.7.0に対応しました。詳しくは「MRTK for Leap Motionの設定方法」をご覧ください。

新しいLeapMotionOrientationExampleシーンを提供してくれた@jackyangzzh氏に感謝します。

**ターゲット・スピーチ・イベントの提起は、もはやゲイズ・ポインターに限定されない**

以前は、ターゲットスピーチイベントは、視線ポインタでフォーカスされたオブジェクトに対してのみ発生させることができました。今回の変更により、どのポインターでフォーカスされても、オブジェクトはスピーチイベントを受け取ることができるようになりました。

![samp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5514d709-905b-08f4-615d-45956d9b6f7a.png)

**TextToSpeechがHTKからMRTKに移植されました。**

敬愛するTextToSpeechスクリプトがついにMRTKに登場！SpeechSynthesizerを使ってUWPプラットフォーム上のテキストから音声を生成することができます。また、この機能を実演するためのサンプルシーンを追加しました。

**OpenXRにおけるシステム提供のモーション・コントローラー・モデルのサポート**
OpenXR上のシステム提供のモーション・コントローラー・モデルを、エディター内とランタイムの両方でサポートするようになりました。

![dd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/781f5a56-c290-32e3-3745-dfa297463088.png)


**OpenXRでのWinMRジェスチャー（選択、ホールド、操作、ナビゲーション）のサポート**

OpenXRにおけるWinMRのジェスチャー（選択、ホールド、操作、ナビゲーション）のサポートを追加しました。#9843.

**OpenXRでのHoloLens 2の関節ハンドメッシュのサポート**

MRTKのサンプルシーンでオンデバイスで動作しているハンドメッシュ
![hand.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d90f0936-b7c6-7cbe-c5d5-f762bd336325.png)



**レガシーWMR、Windows XRプラグイン、OpenXRにおけるコントローラのハプティクスのサポート**

レガシーWMR、Windows XRプラグイン、OpenXRにおけるコントローラのハプティクスのサポートを追加しました。#9735

**HoloLens 2のOpenXRでの空間マッピングのサポート**

HoloLens 2でOpenXRを使用する際に、空間メッシュのサポートを追加しました。#9567および#9827

**Windows XRプラグインでのアイトラッキングのサポート**

Windows XR Pluginの最小バージョン2.7.0(Unity 2019)、4.4.2(Unity 2020)、5.2.2(Unity 2021)を使用する際のアイトラッキングのサポートを追加しました。#9609

**注目すべきバグフィックスと変更点**

- ピンチの検出がよりスムーズになりました。誤ってピンチジェスチャーを落としにくくなりました。#9576
- Object Manipulatorコンポーネントを持つオブジェクトは、フラグが設定されている場合、リリース時に一貫して速度を維持するようになりました。#9733
- バックストレイフィングで床の有無を確認するようになり、カメラが環境に切り取られたり、ユーザーが何もない場所でホバリングするような状況を防ぐことができるようになりました。 #9697
- IsNearObjectが仮想プロパティになり、球体やポケポケを拡張する際に柔軟に対応できるようになりました。#9803
- ボタンに利用可能な音声コマンドを表示する際に、適切なキーワードを表示するようになりました。#9824
- Oculus Controllerが独自のスタンドアローンビジュアライザーを使用するようになり、MRTKのビジュアライズとOculus Integration Packageのビジュアライズとの衝突を防ぐことができるようになりました。#9589
- キーボード関連のスクリプトを、最新のUnityバージョン(2019.4.25+ & 2020.3.2+)での動作に合わせて変更しました。リリース時点では、HoloLensに影響を与える自動補完のバグとTMP Input Fieldのバグ(いずれもMRTKの外部)が残っています。詳細については#9056および#9724をご参照ください。
- スクロールオブジェクトコレクションのパフォーマンスを改善しました。また、コレクション内のGameObjectが複製されるとマテリアルが失われる問題を修正しました。#9813, #9718
- シーン理解のデモスクリプトに、特定の種類の観測されたシーンオブジェクトをすべて取得するGetSceneObjectsOfType関数を追加しました。#9524, #9744
- コマンドラインビルドツールにおいて、sceneListまたはsceneListFileフラグで指定されたシーンのみがビルドに含まれるようになりました（いずれかのフラグが存在する場合）。#9695
- ビルドツールにおいて、msbuild（デフォルトオプション）を使用する代わりに、nuget.exeへのパスを指定し、それを使用してパッケージの復元を行うオプションが新たに追加されました。#9556
- Windows XRプラグインを使用すると、手のジョイントが古くなったり、手のメッシュが二重になったりする問題を修正しました。#9890
- Windows XRプラグインの自動リモーティング機能を使用すると、入力やインタラクションが欠落する問題を修正しました。#9868
- BuildDeployWindowがWindows SDKのパスに無効なREGキーを照会しようとする問題を修正しました。#9664
- MRTKのglTFインポーターがオプションになりました。複数のglTFインポータが存在する場合、カスタムスクリプトの定義シンボルにMRTK_GLTF_IMPORTER_OFFを追加することで、MRTKの使用を無効にすdf`ことができます。#9658
- OpenVRのKnucklesコントローラが正しく検出されない問題を修正しました。#9881
 
**既知の問題**

**オーディオデモにasmdefファイルが含まれていない (UPM pacakge)**
Mixed Reality Feature Toolを介してMRTKをインポートする際、Unity Package ManagerのUIを使ってサンプルやデモがプロジェクトに追加されます。Audioデモをインポートすると、WindowsMicrophoneStreamDemo.unityシーンが正しく動作しなくなります。これは、サンプルの.asmdefファイルが欠落していることが原因です。

この問題を回避するには、以下の手順を実行してください。

- Library/PackageCache/com.microsoft.mixedreality.toolkit.examples@[...]/MRTK.Examples.asmdefを、「Assets/Samples/Mixed Reality Toolkit Examples」フォルダにコピーします。
- コピーしたファイルの名前を「Examples」に変更します。
- Examplesファイルを開きます。
- Name boxで、内容を「Examples」に置き換える
- Apply　をクリックします。
- ビルドとデプロイ

この問題は、今後のMRTKリリースで修正される予定です。

**Unity 2020.3でMRTKのビルドウィンドウが不定形の「Importing assets」ダイアログを引き起こす**

Unity 2020.3のMRTKビルドウィンドウには、UWPビルドの実行に成功した後、「アセットのインポート」ダイアログが完了しないという既知の問題があります。この問題は、Unity社と共同で調査中です。

**Unity 2020におけるText Mesh Pro Canvas Rendererの警告について**

Unity 2020の使用中、ほとんどのMRTKのサンプルシーンで以下の警告が記録されます。

CanvasRendererコンポーネントは必要なくなったので、[TextMeshPro]GameObjectから削除してください。

```txt
Please remove the CanvasRenderer component from the [TextMeshPro] GameObject as this component is no longer necessary.
```

Canvas Rendererの警告はTextMeshProバージョン3.0.3で追加されました。


# MRTK 2.6.1 リリースノート


> 重要
> 
> ARM64 を使用する Microsoft HoloLens 2 用に構築されたアプリケーションに影響を与える既知のコンパイラ問題があります。この問題は、Visual Studio 2019 をバージョン 16.8 以降にアップデートすることで修正されます。Visual Studioをアップデートできない場合は、com.microsoft.mixedreality.toolkit.toolsパッケージをインポートして回避策を適用してください。


**2.6.1の主な変更点**

**HoloLens 2 / UWPでOpenXRが動作しない問題を修正しました。**

MRTKのOpenXRサポートがUWP上で実行できないリグレッションを修正しました。

**Leap MotionのObjectManipulatorが回転しない問題を修正しました。**

Leap Motionのハンドの回転がObjectManipulatorスクリプトで考慮されないリグレッションを修正しました。

**サンプルシーンの更新**

Unityプラグインの出荷時の状態を正しく反映するために、シーン理解のサンプルシーンを更新します。また、空間認識サンプルシーンがインポートされているかどうかに依存しないように更新しました。2.6.1にアップデートする前に、インポートされたシーン理解サンプルと空間認識サンプルがプロジェクト内に存在する場合は、競合の可能性を避けるために削除してください。これらのサンプルを削除せず、コンソールでこれらに関連したコンフリクトが表示される場合は、両方のサンプル(またはAssets/ Samples/Mixed Reality Toolkit Examplesフォルダ)を削除してから、再度インポートを試みてください。

現在のダイアログのシナリオを正しく表現するために、ダイアログのサンプルシーンを更新しました。

**2.6.0の主な変更点**

**OpenXRのサポートの追加**

Unity社のOpenXRプレビューパッケージおよびMicrosoft社のMixed Reality OpenXRパッケージの初期サポートを追加しました。詳細については、MRTK/XRSDKのスタートページ、Unityのフォーラムポスト、Microsoftのドキュメントをご参照ください。


> 重要
> 
> UnityのOpenXRは、Unity2020.2以降でのみサポートされています。
> 
> また、現在はx64とARM64のビルドのみをサポートしています。


**Asset swap utility**

新しいアセット・スワップ・ユーティリティーを使って、Unityのシーンにある複数のアセットを交換することができます。

**HPモーションコントローラーがMRTKでサポートされました**

HP Reverb G2用のコントローラがMRTKでネイティブに動作するようになりました。

**実験的なインタラクティブエレメントとステートビジュアライザー**

Interactive Elementは、MRTKの入力システムへのシンプルで集中的なエントリーポイントです。Interactive Elementには、Core Interaction Statesの状態管理メソッド、イベント管理、状態設定ロジックが含まれています。詳細はInteractive Element Documentationを参照してください。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/863793a5-1b77-6b50-dca8-3ed695e6d2e6.png)


State Visualizerは、Interactive Elementに依存するアニメーションコンポーネントです。このコンポーネントは、アニメーションクリップの作成、キーフレームの設定、Animator State Machineの生成を行います。詳細については、State Visualizerのドキュメントを参照してください。

![139.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fcc220b7-af79-de7b-1656-9f5d28b639f4.png)


**テレポートジェスチャーによるテレポートがすべてのプラットフォームでサポートされるようになりました。**

すべてのプラットフォームで、テレポートジェスチャーを使ってプレイスペース内を移動できるようになりました。デフォルトの設定のMRデバイスでコントローラを使ってテレポートするには、サムスティックを使います。多関節の手でテレポートするには、手のひらを上に向け、人差し指と親指を外側に突き出すようなジェスチャーをし、人差し指を丸めてテレポートを完了させます。入力シミュレーションでテレポートするには、最新の入力シミュレーションサービスのドキュメントを参照してください。

![191.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/75245eb1-6b3a-fa67-29cf-403a4686c02e.png)


**MRTKで実験的な空間認識オブザーバーとしてScene Understandingが利用可能に**

MRTK 2.6では、シーン理解の実験的なサポートが導入されています。ユーザーはHoloLens 2のシーン理解機能をMRTKベースのプロジェクトの空間認識オブザーバーとして組み込むことができます。詳細については、Scene Understandingのドキュメントをお読みください。


> 重要
> 
> Scene Understandingは、HoloLens 2とUnity 2019.4以降でのみサポートされています。

この機能にはScene Understandingパッケージが必要ですが、現在はMixed Reality Feature Toolから入手できます。Mixed Reality Feature Tool を使用する場合、または UPM 経由でインポートする場合は、依存関係の問題があるため、Experimental - SceneUnderstanding サンプルをインポートする前に、Demos - SpatialAwareness サンプルをインポートしてください。詳しくは、こちらのGitHub issueをご覧ください。

[Mixed Reality Feature Tool](https://aka.ms/MRFeatureTool)

![170.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/615cb08a-6e46-c783-e8b5-96ed50c34611.png)


**ランタイム・プロファイル・スイッチングのサポート**

MRTKでは、MRTKインスタンスの初期化前（すなわちPre MRTK initialization profile switch）と、プロファイルがアクティブに使用された後（すなわちActive profile switch）の両方でプロファイルの切り替えが可能になりました。前者のスイッチはハードウェアの能力に基づいて選択したコンポーネントを有効にするために使用でき、後者のスイッチはユーザーがアプリケーションのサブパートに入ったときにエクスペリエンスを変更するために使用できます。詳細やコードサンプルについては、プロファイルスイッチに関するドキュメントをご覧ください。

**方向指示器とフォローのソルバーがexperimental(実験段階)から卒業**

2つの新しいソルバーがメインラインのMRTKで使用できるようになりました。

![45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/526e6e8b-5776-b15e-0cbb-d7336dee95e6.png)


**ハンドコーチがexperimental(実験段階)から卒業**

Hand Coach機能がメインラインのMRTKで使用できるようになりました。

![85.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1617b174-7388-c020-b293-e8dc634f03bd.png)

**ダイアログ・コントロールがexperimental(実験段階)から卒業**

ダイアログコントロールがメインラインのMRTKで使用できるようになりました。

![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/07224cf9-7c20-2abc-6b98-6e29451a6615.png)

**パルスシェーダがexperimental(実験段階)から卒業**

Pulseシェーダのスクリプトがexperimentalから卒業しました。詳細については以下を参照してください。パルスシェーダ ドキュメント

![260.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/40daf7bd-2d43-7b46-738f-ed98b911bdb8.png)


**Input Recording Service(入力記録サービス)の改善**

InputRecordingServiceとInputPlaybackServiceで視線入力の記録と再生ができるようになりました。録画の最適化により、録画中のフレームレートが一定に保たれるようになり、録画ファイルのサイズと保存時間も約50％削減されました。録画ファイルの保存と読み込みを非同期で行うことができるようになりました。なお、今回のMRTKでは録画ファイルのフォーマットが変更されていますので、新しいバージョン1.1の仕様についてはこちらをご覧ください。

**読み込みモード**

HoloLens 2のリーディングモードに対応しました。リーディングモードでは、システムの視野が狭くなりますが、Unityの出力のスケーリングがなくなります。Unityでレンダリングされたピクセルは、HoloLens 2で投影されたピクセルに対応します。アプリケーション作成者は、複数の人でテストを行い、このトレードオフが自分のアプリケーションに必要かどうかを確認する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e4ef2a72-d40f-7d43-538a-4663a83a844c.png)

**UWPでの3Dアプリケーションランチャーのサポート**

UWPに3Dアプリのランチャーを設定する機能を追加しました。この設定は、MRTKビルドウィンドウとMRTKプロジェクト設定の「ビルド設定」の両方で公開されます。また、Unityでのビルド時に自動的にプロジェクトに書き込まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/600415b9-5608-af36-a4ad-400946325463.png)

**幾つかの変更点**

**インポートされたGLTFオブジェクトの一部のフィールドが大文字になる**

デシリアライゼーションに関連する問題のため、インポートされたGLTFオブジェクトの一部のフィールドが大文字で始まるようになりました。影響を受けるフィールドは以下の通りです（新しい名前で表示）。ComponentType, Path, Interpolation, Target, Type, Mode, MagFilter, MinFilter, WrapS, WrapT.

**入力アニメーション・バイナリファイルのフォーマットがバージョン1.1に更新されました**

InputRecordingServiceとInputPlaybackServiceで使用されている入力アニメーションのバイナリファイルは、これら2つのサービスで行われた最適化を有効にするために、ファイルフォーマットが更新されました。新しいバージョン1.1の仕様については、こちらをご覧ください。

**MSBuild for Unityのサポート**
Unityの新しいパッケージガイダンスに合わせて、MSBuild for Unityのサポートは2.5.2のリリースで削除されました。

**既知の問題**

**OpenXR**
現在、Holographic RemotingとOpenXRには、ハンドジョイントが一貫して利用できないという既知の問題があります。また、アイトラッキングのサンプルシーンは現在互換性がありませんが、アイトラッキングは機能します。

**Mixed Reality Toolkit Standard Shaderの一部の機能には、Foundationパッケージが必要です。**

Unity Package Manager経由でインポートした場合、MRTK Standard Shaderのユーティリティスクリプト（例：HoverLight.cs）はStandard Assetsパッケージ内のシェーダーと一緒に配置されていません。この機能を利用するには、アプリケーションでFoundationパッケージをインポートする必要があります。

**シャットダウン時にCameraCacheが新しいカメラを作成することがある**

一部の状況（Unity EditorでLeapMotionプロバイダを使用している場合など）では、シャットダウン時にCameraCacheがMainCameraを再作成する可能性があります。詳細については、この問題を参照してください。

**Unity Package Manager経由でサンプルをインポートするとFileNotFoundExceptionが発生する**

プロジェクトパスの長さによっては、Unity Package Manager経由でサンプルをインポートすると、UnityコンソールにFileNotFoundExceptionメッセージが表示されることがあります。この原因は、「見つからない」ファイルのパスがMAX_PATH(256文字)よりも長いことにあります。解決するには、プロジェクトパスの長さを短くしてください。

**空間化装置が指定されていません。アプリケーションがSpatial Soundをサポートしません。**

オーディオ・スペーシャライザーが設定されていないと、「No spatializer was specified」という警告が表示されます。これは、XRパッケージがインストールされていない場合に発生する可能性があります。これは、UnityがこれらのパッケージにSpatializerを含むためです。

解決するには、以下を確認してください。

- Window > Package Managerに1つ以上のXRパッケージがインストールされている。
- Mixed Reality Toolkit」→「Utilities」→「Configure Unity Project」で「Audio Spatializer」を選択します。

![87.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1a807b4b-c924-2c7e-ce65-90a4d56bf886.png)


**NullReferenceException: Object reference not set to an instance of an object (SceneTransitionService.Initialize)**

状況によっては、EyeTrackingDemo-00-RootSceneを開くと、SceneTransitionServiceクラスのInitializeメソッドでNullReferenceExceptionが発生する場合があります。このエラーは、Scene Transition Serviceの構成プロファイルが設定されていないことが原因です。解決するには、以下の手順で行ってください。

- ヒエラルキー内のMixedRealityToolkitオブジェクトに移動します。
- Inspectorウィンドウで「Extensions」を選択します。
- 展開されていない場合は、Scene Transition Serviceを展開してください。
- Configuration Profileの値を「MRTKExamplesHubSceneTransitionServiceProfile」に設定してください。
  
![32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7dc5a5d9-832e-27d8-c5ba-e4c3ba03ab0d.png)


**Oculus Quest**

現在、Oculus XRプラグインをStandaloneプラットフォームをターゲットにして使用する際に、既知の問題があります。Oculusのバグトラッカー/フォーラム/リリースノートで最新情報を確認してください。

この問題は、以下の3つのエラーで示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5fc3a28d-2d85-c482-6b02-e497dca044b7.png)

**UnityUIとTextMeshPro**

TextMeshProの新しいバージョン（1.5.0+または2.1.1+）では、ドロップダウンのデフォルトのフォントサイズとボールドフォントの文字間隔が変更されるという既知の問題があります。

![33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a704254a-fc1a-35ba-125a-3c80a120f69d.png)

この問題は、TextMeshProを以前のバージョンにダウングレードすることで回避できます。詳細は issue #8556 を参照してください。


# アーキテクチャの概要

MRTKの内容を全体的に紹介するために、このドキュメントに含まれるアーキテクチャ情報は、以下のことを理解するのに役立ちます。

- MRTKの大きな構成要素とその接続方法
- バニラUnityには存在しないかもしれない、MRTKが導入する概念
- 大きなシステム（Inputなど）の仕組み

このセクションは、タスクの実行方法を教えるものではなく、そのようなタスクがどのように構成されているか、そしてその理由を教えるものです。

**多くのオーディエンス、1つのツールキット**

MRTKには単一の統一された読者がいるわけではありません。初めてのハッカソンから、企業向けに複雑な共有体験を構築する個人まで、さまざまなユースケースをサポートするために書かれています。コードやAPIの中には、どちらかに最適化されたものもあるかもしれませんが（例えば、MRTKの一部は「ワンクリック・コンフィグレーション」に最適化されているように見えます）、それらの中には歴史的な理由や資源的な理由によるものもあることに留意する必要があります。MRTKの進化に伴い、構築される機能はユースケースの範囲をサポートするために拡張できるように設計されるべきである。

また、MRTKにはVRやARの体験を優雅に拡張するための要件もあります。HoloLens 2やHoloLens 1にデプロイされたときに動作を緩やかにフォールバックさせるアプリケーションを簡単に構築でき、OpenVRやWMR（およびその他のプラットフォーム）を対象としたアプリケーションを簡単に構築できるようにする必要があります。また、OpenVRやWMR（およびその他のプラットフォーム）を対象としたアプリケーションを簡単に構築することも必要です。チームは、特定のシステムやプラットフォームに特定のイテレーションを集中させることもありますが、長期的な目標は、人々がMixed Reality体験を構築する場所に幅広く対応することです。

**ハイレベルな内訳**

MRTKは、Mixed Reality（MR）の体験を迅速に開始するためのツール群であると同時に、独自のランタイムや拡張方法、構成方法について意見を持つアプリケーションフレームワークでもあります。

高いレベルでは、MRTKは以下のように分解することができます。

![142.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/45cb8ee1-54eb-228b-1573-2201c4986403.png)



MRTKには、他の部分にほとんど依存しない福袋的なユーティリティも含まれている（いくつか例を挙げると、ビルドツール、ソルバー、オーディオ・インフルエンサー、スムージング・ユーティリティ、ライン・レンダラー）。

アーキテクチャドキュメントの残りの部分は、フレームワークとランタイムから始まり、入力などのより興味深く複雑なシステムへと、ボトムアップで構築されていきます。アーキテクチャの概要については、目次を参照してください。

**API Reference**

https://docs.microsoft.com/en-us/dotnet/api/Microsoft.MixedReality.Toolkit

## 入力システム（Input System）

MRTKの入力システムでは、以下のことが可能です。

- 6自由度のコントローラ、アーティキュレーテッドハンド、スピーチなど、さまざまな入力ソースからの入力を、入力イベントを介して受け取ることができます。
- 選択」や「メニュー」などの抽象的なアクションを定義し、それをさまざまな入力に関連付けることができます。
- コントローラに接続されたポインターを設定し、フォーカスイベントやポインターイベントによってUIコンポーネントを駆動する。
 
![inputsystem.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8a988f46-6f8c-07c2-c324-19c4a8cfc0ee.png)


入力は入力データ・プロバイダ（デバイス・マネージャ）によって生成される。各プロバイダは特定の入力ソースに対応しています。Open VR、Windows Mixed Reality（WMR）、Unity Joystick、Windows Speechなど。プロバイダは、Mixed Reality ToolkitコンポーネントのRegistered Service Providers Profileを介してプロジェクトに追加され、対応する入力ソースが利用可能になると、自動的に入力イベントを生成します（WMRコントローラが検出されたときや、ゲームパッドが接続されたときなど）。

入力アクションは、生の入力を抽象化したもので、入力を生成する特定の入力ソースからアプリケーションロジックを分離するのに役立ちます。例えば、Selectアクションを定義し、それをマウスの左ボタン、ゲームパッドのボタン、6DOFコントローラのトリガーにマッピングすると便利です。そうすれば、アプリケーションロジックはSelect入力アクションイベントをリッスンすることができ、イベントを発生させる様々な入力を意識する必要がなくなります。入力アクションは、Mixed Reality ToolkitコンポーネントのInput System Profile内にあるInput Actions Profileで定義されます。

コントローラは、入力デバイスが検出されたときに入力プロバイダによって作成され、紛失や切断されたときに破棄されます。例えば、WMR入力プロバイダは、6 DOFデバイス用のWMRコントローラと、多関節ハンド用のWMR多関節ハンドコントローラを作成します。コントローラの入力は、Input System Profileの中のController Mapping Profileを介して、入力アクションにマッピングできます。コントローラから発生する入力イベントには、関連する入力アクションが含まれます。

コントローラーにはポインターを付けることができ、シーンを照会してフォーカスのあるゲームオブジェクトを特定し、それに対してポインターイベントを発生させます。例えば、ラインポインターがシーンに対してレイキャストを行い、コントローラのポーズを使ってレイの原点と方向を計算します。各コントローラに作成されるポインターは、Input System Profileの下のPointer Profileで設定されます。

![246.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5d773965-c00f-93e2-cb42-d92a0b3906a0.png)


UIコンポーネントで入力イベントを直接処理することもできますが、実装をデバイスに依存しないようにするためには、ポインタイベントを使用することをお勧めします。

MRTKでは、デバイスに依存しない方法で入力状態を直接問い合わせるためのいくつかの便利なメソッドも提供しています。詳細は「MRTKで入力状態にアクセスする」を参照してください。

# Hand tracking(HoloLens2のみ)

**手の追跡プロファイル**

Hand Tracking profileは、Input System profileの中でカスタム設定ができます。
![238.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a8c49be9-1e65-7186-e109-ac88323acf9b.png)


https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/input/hand-tracking?view=mrtkunity-2021-01

**Joint prefabs(共同プレハブ)**

- Joint prefabsは、simple prefabsを使用して視覚化される
- 手のひら（Palm）と人差し指の関節（Index Finger）が特に重要
- デフォルトでは、hand joint prefabsはsimple geometric primitives（単純な幾何学的プリミティブ）です。これらは必要に応じて交換できます。プレハブがまったく指定されていない場合は、代わりに空のGameObjectが作成されます。　

![253.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9129b46f-38e1-510b-a90a-79522badca86.png)


**Hand mesh prefab**

- 手のメッシュは、ハンドトラッキングデバイスから完全に定義されたメッシュデータが提供されている場合に使用されます
- プレハブのレンダリング可能なメッシュはデバイスからのデータで置き換えられるので、立方体などのダミーメッシュで十分です。手のメッシュには、プレハブのマテリアルが使われます
- ハンドメッシュ表示は、パフォーマンスに顕著な影響を与える可能性があります。このため、[ハンドメッシュの視覚化を有効にする]オプションをオフにすると、完全に無効にできます。
- 一般に、手の状態をわかりやすくするためにUnityエディターで視覚化をオンにし、パフォーマンスの問題からプレイヤー上ではオフにすることがおすすめ
- 手の位置と回転は、個々の手関節の入力システムからとして要求できます　[MixedRealityPose](https://docs.microsoft.com/en-us/dotnet/api/microsoft.mixedreality.toolkit.utilities.mixedrealitypose?view=mixed-reality-toolkit-unity-2020-dotnet-2.6.0)

![34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d2ec3d50-c061-f355-4ba7-37e917a19c88.png)

# Eye tracking　視線追跡(HoloLens2のみ)

![183.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fc1c15bf-603c-0561-be9a-d36c48bb8cad.png)

アイトラッキングは、ユーザーが視野内のホログラムに素早く楽に関わることを可能にし、ユーザーの意図をより良く識別することで、システムをより賢くすることができます。ここでは、視線を使ったインタラクションのベストプラクティスを示す既存のアイトラッキング・サンプルを参考に見ていきます。

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/input/eye-tracking/eye-tracking-main?view=mrtkunity-2021-01

**サンプル**

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/example-scenes/eye-tracking-examples-overview?view=mrtkunity-2021-01

このトピックでは、MRTKのアイトラッキング・サンプル（Assets/MRTK/Examples/Demos/EyeTracking）をもとに、MRTKでアイトラッキングをすばやく始める方法を説明します。
デモには、暗黙的な視線による操作から、見ているものの情報を音声や手の入力とシームレスに組み合わせる方法まで、さまざまな使用例が含まれています。これにより、ユーザーは対象物を見て「Select(選択）」と言ったり、手のジェスチャーをするだけで、ホログラフィックコンテンツを素早く楽に選択し、視界全体に移動させることができます。また、スレート上のテキストや画像を視線方向にスクロール、パン、ズームする例も紹介されています。最後に、2Dスレート上でユーザーの視覚的な注意を記録し、視覚化する例を紹介します。以下のセクションでは、MRTKのアイトラッキング・サンプル・パッケージ（Assets/MRTK/Examples/Demos/EyeTracking）に含まれる各サンプルの内容について詳しく説明しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/dfeedbad-2536-b33f-c231-12bd96463c28.png)

- 視線によるターゲット選択
    - 概要：目、声、手の入力を組み合わせて、迅速かつ楽にターゲットを選択することができます。
- 視線誘導型ナビゲーション
    - 概要：目、声、手の入力を組み合わせて、スクロール、パン、ズーム、3D回転などの操作を行います。
- 視線による位置決め
    - 概要：目、声、手の入力（ドラッグ＆ドロップ）によるホログラムの位置決め。視線＋手によるスライダのサポート。
- 視線の可視化
    - 概要：スレート上の2次元アテンションマップ（ヒートマップ）。アイトラッキングデータの記録＆再生。



# Mixed Reality Toolkitプロファイル設定ガイド

![90.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6a0e5197-12e3-a9f0-85d7-055aec049270.png)


Mixed Reality Toolkitでは、ツールキットの管理に必要な設定を可能な限り一元化しています（真のランタイム「things」を除く）。

このガイドは、現在ツールキットで利用可能な構成プロファイル画面のそれぞれについて、簡単なウォークスルーを行っています。

## Mixed Reality Toolkitのメイン構成プロファイル
メインの設定プロファイルは、シーン内のMixedRealityToolkit GameObjectにアタッチされ、プロジェクトにおけるツールキットのメインのエントリーポイントとなります。

> 注意点
> 
> Mixed Reality Toolkitは、デフォルトの設定画面を「ロック」して、プロジェクトの共通のスタートポイントを常に確保するようにしています。MRTKの設定はプレイモード中は編集できません。


![162.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4e9a405c-64ec-4bbb-0e9d-c09f51ca2790.png)


複合現実感ツールキットのすべての「デフォルト」プロファイルは、SDKプロジェクトのAssets/MRTK/SDK/Profilesフォルダにあります。

> 重要
>
> DefaultHoloLens2ConfigurationProfileは、HoloLens 2用に最適化されています。詳細は、「Profiles」を参照してください。

メインのMixed Reality Toolkit Configuration Profileを開くと、インスペクタに次のような画面が表示されます。

![172.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1ad41a51-67ea-37e7-cbd2-da2fe576790e.png)


シーンにMixedRealityToolkitが入っていない状態でMixedRealityToolkitConfigurationProfileのアセットを選択すると、MRTKにシーンを自動的にセットアップさせるかどうかを尋ねてきます。これはオプションですが、すべての設定画面にアクセスするためには、シーン内にアクティブなMixedRealityToolkitオブジェクトが存在しなければなりません。

ここには、プロジェクトの現在のアクティブなランタイム・コンフィギュレーションが格納されています。

ここから、以下のようなMRTKのすべての構成プロファイルに移動することができます。

- Mixed Reality Toolkitのプロファイル設定ガイド
  - メインのMixed Reality Toolkit構成プロファイル
  - [Experience settings (エクスペリエンス設定)](#エクスペリエンス設定)
  - [Camera settings (カメラの設定)](#カメラの設定)
  - [Input system settings (入力システムの設定)](#入力システムの設定)
  - [Boundary visualization settings (境界線の可視化設定)](#境界線の可視化設定)
  - [Teleportation system selection (テレポーテーション・システムの選択)](#テレポーテーション・システムの選択)
  - [Spatial awareness settings (空間認識機能の設定)](#空間認識機能の設定)
  - [Diagnostics settings (診断機能の設定)](#診断機能の設定)
  - [Scene system settings (シーンシステムの設定)](#シーンシステムの設定)
  - [Additional services settings (追加サービスの設定)](#追加サービスの設定)
  - [Input actions settings (入力動作の設定)](#入力動作の設定)
  - [Input actions rules (入力動作のルール)](#入力動作のルール)
  - [Pointer configuration (ポインターの設定)](#ポインターの設定)
  - [Gestures configuration (ジェスチャーの設定)](#ジェスチャーの設定)
  - [Speech commands (音声コマンド)](#音声コマンド)
  - [Controller mapping configuration (コントローラのマッピング設定)](#コントローラのマッピング設定)
  - [Controller visualization settings (コントローラの可視化設定)](#コントローラの可視化設定)
  - [Editor utilities (エディターユーティリティ)](#エディターユーティリティ)
    - [Service inspectors (サービスインスペクタ)](#サービスインスペクタ)
    - [Depth buffer renderer (深度バッファレンダラ)](#深度バッファレンダラ)
  - [Changing profiles at runtime (ランタイムでのプロファイル変更)](#ランタイムでのプロファイル変更)
    - [Pre MRTK initialization profile switch (MRTK初期化前のプロファイル切り替え)](#MRTK初期化前のプロファイル切り替え)
    - [Active profile switch (アクティブ・プロファイル・スイッチ)](#アクティブ・プロファイル・スイッチ)
    
これらの設定プロファイルについては、以下の関連セクションで詳しく説明します。

## エクスペリエンス設定
Experience settings

この設定は、Mixed Reality Toolkitのメイン設定ページにあり、お客様のプロジェクトにおけるMixed Reality環境のスケールのデフォルトの動作を定義します。

![57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2cf5587e-1bc2-9c21-2779-12f730a99a7b.png)


## カメラの設定
Camera settings

カメラ設定では、お客様の複合現実感プロジェクトでのカメラのセットアップ方法を定義し、一般的なクリッピング、品質、透明度の設定を定義します。

![97.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d1134445-f072-cdda-3dce-bcdc8d70e9d0.png)



## 入力システムの設定
Input system settings

Mixed Realityプロジェクトでは、すべての入力イベントをプロジェクト内でルーティングするために、堅牢でよく訓練された入力システムが提供されています。

![158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2e8aed53-d035-19fb-17f5-bb457ee0f737.png)


MRTKが提供する入力システムの背後には、いくつかの他のシステムがあります。これらのシステムは、マルチプラットフォーム／Mixed Realityフレームワークの複雑さを抽象化するために必要な、複雑な相互関係の駆動と管理を支援します。

![225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/13e239c7-c5b6-bc44-1d5f-be245eab96f7.png)


それぞれのプロファイルの詳細は以下の通りです。

- Focus Settings (フォーカス設定)
- Input actions settings (入力動作の設定)
- Input actions rules (入力動作のルール)
- Pointer configuration (ポインターの設定)
- Gestures configuration (ジェスチャーの設定)
- Speech commands (音声コマンド)
- Controller mapping configuration (コントローラのマッピング設定)
- Controller visualization settings (コントローラの可視化設定)


## 境界線の可視化設定
Boundary visualization settings

バウンダリ システムは、基盤となるプラットフォームのバウンダリ/ガーディアン システムによって報告された知覚された境界を変換します。バウンダリ ビジュアライザーの設定により、シーン内に記録されたバウンダリをユーザーの位置に対して自動的に表示することができます。バウンダリは、ユーザーがシーン内でテレポートした場所に基づいて反応/更新されます。

![89.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0a1288f6-655f-fc00-c15a-fc6217ac7f55.png)

## テレポーテーション・システムの選択
Teleportation system selection

Mixed Reality Projectでは、プロジェクト内のテレポートイベントを管理するために、フル機能のテレポートシステムが提供されており、デフォルトで選択されています。

![118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/98c65999-4cf1-e1ea-9f7b-aa42d75bd098.png)


## 空間認識機能の設定
Spatial awareness settings

複合現実感プロジェクトでは、デフォルトで選択されている、空間スキャンシステムを扱うための再構築された空間認識システムを提供しています。

![250.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a34b509e-23a8-9ee8-0dc0-0777f8bbe316.png)



Mixed Reality Toolkitの空間認識設定では、システムの起動方法（アプリケーションの起動時に自動的に起動するか、後からプログラムで起動するか）を調整したり、視野のエクステントを設定したりできます。

また、メッシュやサーフェスの設定を行い、プロジェクトが周囲の環境を理解する方法をさらにカスタマイズすることができます。

この機能は、スキャンされた環境を提供できるデバイスにのみ適用されます。

![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/baa15be0-a074-32a4-724a-daf427bb4699.png)



## 診断機能の設定
Diagnostics settings

MRTKのオプション機能として、非常に便利なプラグイン診断機能が用意されています。

![154.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9c2927bc-7c7f-8d6e-0c4e-0115656e790c.png)


診断プロファイルには、プロジェクトの実行中にモニターするためのいくつかの簡単なシステムが用意されており、シーン内のディスプレイ・パネルを有効／無効にする便利なオン／オフ・スイッチも含まれています。

![58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/45fc581e-d156-5ed6-3e18-763a2f0c77ff.png)


## シーンシステムの設定
Scene system settings

MRTKでは、複雑な付加価値のあるシーンのローディング/アンローディングを管理するために、このオプションサービスを提供しています。お客様のプロジェクトにScene Systemが適しているかどうかを判断するために、Scene System Getting Started Guideをお読みください。

![105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/cb543a55-cd8b-8d81-80b1-b922d996b191.png)

## 追加サービスの設定
Additional services settings

Mixed Reality Toolkitの先進的な部分の一つに、サービスロケータ・パターンの実装があり、フレームワークに任意の「サービス」を登録することができます。これにより、フレームワークは新しい機能やシステムで簡単に拡張できるだけでなく、プロジェクトがこの機能を利用して独自のランタイム・コンポーネントを登録することもできます。

登録されたサービスは、MonoBehaviourや煩雑なシングルトン・パターンを実装するためのオーバーヘッドやコストをかけずに、Unityのすべてのイベントを最大限に活用することができます。これにより、フォアグラウンドとバックグラウンドの両方のプロセスを実行するためのシーンオーバーヘッドのない純粋なC#コンポーネント、例えば、システムのスポーン、ランタイムゲームロジックなど、実質的にあらゆるものが可能になります。

![60.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/009c13ce-3f62-566c-149d-d7025feea4cb.png)


## 入力動作の設定
Input actions settings

入力アクションは、ランタイムプロジェクトから物理的なインタラクションや入力を抽象化する方法を提供します。コントローラや手、マウスなどからの物理的な入力はすべて、ランタイムプロジェクトで使用するための論理的な入力アクションに変換されます。これにより、どこから入力されたかに関わらず、プロジェクトはこれらのアクションを「やるべきこと」や「インタラクトすること」としてシーンに実装することができます。

新しい入力アクションを作成するには、"Add a new Action "ボタンをクリックして、それが何を表すのかわかりやすいテキスト名を入力します。その後、アクションが伝えるべき軸（データの種類）を選択するか、フィジカルコントローラの場合は、取り付け可能なフィジカル入力タイプを選択するだけです。

|Axis Constraint|Data Type|Description|Example use|
|:----|:----|:----|:----|
|None|No data|空のアクションやイベントに使用される|Event Trigger|
|Raw (reserved)|object|将来の使用のための予約|N/A|
|Digital|bool|ブール型のON/OFFデータ|A controller button|
|Single Axis|float|単精度データ値|トリガーなどのレンジ入力|
|Dual Axis|Vector2|多軸用のデュアルフロート型データ|DpadまたはThumbstick|
|Three Dof Position|Vector3|3つのフロート軸からなる位置情報データ|3Dポジションスタイル専用コントローラー|
|Three Dof Rotation|Quaternion|4つのフロート軸で回転方向のみの入力|Oculus Goコントローラーなどの三度式コントローラー|
|Six Dof|Mixed Reality Pose (Vector3, Quaternion)|Vector3とQuaternionの両方のコンポーネントを持つ位置と回転スタイルの入力|モーションコントローラやポインター|


> 注意点
> 
> 入力アクションは、ランタイムで編集できない数少ないコンポーネントの1つで、設計時にのみ設定されます。このプロファイルは、各アクションに生成されるIDにフレームワーク（そしてプロジェクト）が依存しているため、プロジェクトの実行中に交換してはいけません。

![140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/12421e65-ba2f-abbb-4d68-86a0ebafe824.png)


## 入力動作のルール
Input actions rules

入力アクションルールは、ある入力アクションに対して発生したイベントを、そのデータ値に基づいて異なるアクションに自動的に変換する方法を提供します。これらはフレームワーク内でシームレスに管理され、パフォーマンスコストは発生しません。

例えば、DPadからの2軸入力イベントを、4つの対応する「Dpad Up」/「DPad Down」/「Dpad Left」/「Dpad Right」アクションに変換することができます（以下の画像を参照）。

これは自分のコードでもできます。しかし、これは非常に一般的なパターンであったため、フレームワークはこれを "すぐに "実行できるメカニズムを提供しています。

入力アクションルールは、利用可能なすべての入力軸に対して設定できます。ただし、ある軸タイプの入力アクションは、同じ軸タイプの別の入力アクションに変換できます。2軸のアクションを別の2軸のアクションにマッピングすることはできますが、デジタルまたはNoneのアクションにはマッピングできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8f8acc28-3d9d-8dd7-b734-608b8cbc0e17.png)


## ポインターの設定
Pointer configuration

ポインターは、任意の入力デバイスからシーンのインタラクティブ性を高めるために使用され、シーン内の任意のオブジェクト（コライダが接続されているか、UIコンポーネントである）に対して方向とヒットテストの両方を与えます。ポインターはデフォルトで、コントローラー、ヘッドセット（注視／フォーカス）、マウス／タッチ入力用に自動的に設定されます。

ポインターは、MRTK IMixedRealityPointerインターフェイスを実装していれば、Mixed Reality Toolkitで提供されている多くのラインコンポーネントの1つ、または独自のものを使用して、アクティブなシーン内で視覚化することもできます。

![257.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/566dd20b-c166-3f09-07ab-faf710820fa7.png)



- Pointing Extent: ゲイズを含むすべてのポインターのグローバルなポインティング エクステントを決定します。
- Pointing Raycast Layer Masks: Pointing Raycast Layer Masks: どのレイヤーに対してポインターがレイキャストするかを決定します。
- Debug Draw Pointing Rays: レイキャスティングに使用される光線を視覚化するためのデバッグ ヘルパーです。
- Debug Draw Pointing Rays Colors: 可視化に使用する色のセットです。
- Gaze cursor prefab: どんなシーンでも、グローバルなゲイズカーソルを簡単に指定できます。

また、必要に応じて Gaze Provider にジャンプして Gaze の特定の値をオーバーライドするヘルパー ボタンもあります。


## ジェスチャーの設定
Gestures configuration

ジェスチャーは、様々なSDK（HoloLensなど）が提供する様々な「ジェスチャー」入力メソッドに入力アクションを割り当てることができる、システム固有の実装です。

> 備考
>
> 現在のジェスチャーの実装はHoloLens専用ですが、将来的にツールキットに追加された他のシステム用に拡張される予定です（時期は未定）。

![230.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a8a9622a-5f7a-813a-890e-e6d660a564b3.png)


## 音声コマンド
Speech commands

ジェスチャーと同様に、一部のランタイムプラットフォームでは、Unityプロジェクトが受信できるコマンドを生成する機能を備えたインテリジェントな「Speech to Text」機能も提供しています。この設定プロファイルでは、以下の設定を行うことができます。

- General Settings - 「Start Behavior」を「Auto Start」または「Manual Start」に設定すると、入力システムの起動時に KeywordRecognizer を初期化するか、プロジェクトが KeywordRecognizer を初期化するタイミングを決定するかが決まります。「Recognition Confidence Level(認識信頼度)」は、UnityのKeywordRecognizer APIの初期化に使用されます。
- スピーチコマンド - 「言葉」を登録し、プロジェクトが受け取ることのできる入力アクションに変換します。また、必要に応じてキーボードアクションに添付することもできます。


> 重要
>
> このシステムは現在、HoloLensやWindows 10デスクトップなどのWindows 10プラットフォーム上で動作する場合にのみ音声をサポートしていますが、将来的にMRTKに追加される他のシステム向けにも強化される予定です（時期は未定）。

![229.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e435b7e6-dcf6-3407-dd29-2604aa255db5.png)


## コントローラのマッピング設定
Controller mapping configuration

Mixed Reality Toolkitの中核となる設定画面の1つに、プロジェクトで利用可能な様々なタイプのコントローラーを設定し、マッピングする機能があります。

以下の設定画面では、現在ツールキットで認識されているコントローラのいずれかを設定することができます。

![237.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f5a74416-588d-7eb8-806a-aeb487bd3774.png)

MRTKでは、以下のコントローラ／システムのデフォルト設定を提供しています。

- Mouse（3D空間マウスのサポートを含む
- Touch Screen
- Xboxコントローラ
- Windows Mixed Realityコントローラ
- HoloLensジェスチャー
- HTC Vive ワンドコントローラ
- Oculus Touchコントローラ
- Oculus Remoteコントローラ
- 汎用のOpenVRデバイス（上級者のみ

事前に構築されたコントローラシステムの画像をクリックすると、対応するすべての入力に対して単一の入力アクションを設定することができます。例えば、以下のOculus Touchコントローラの設定画面を参照してください。


![78.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2bc4da03-bbf1-39d6-c603-24d777289093.png)

また、上記以外のOpenVRやUnityの入力コントローラーを設定するための詳細画面もあります。


## コントローラの可視化設定
Controller visualization settings

コントローラのマッピングに加えて、シーン内でのコントローラの表示方法をカスタマイズするための設定プロファイルが用意されています。

これは、「グローバル」（特定のハンド用のコントローラのすべてのインスタンス）または個々のコントローラタイプ/ハンドに固有に設定することができます。

MRTKは、Windows Mixed RealityとOpenVR用のネイティブSDKコントローラモデルもサポートしています。これらはシーンにGameObjectとしてロードされ、プラットフォームのコントローラ・トラッキングを使って配置されます。

シーン内のコントローラー表現を物理的なコントローラー位置からオフセットする必要がある場合は、コントローラーモデルのプレハブに対してオフセットを設定するだけです（例：コントローラープレハブのトランスフォーム位置にオフセット位置を設定する）。

![129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c2fc9520-2600-5cb0-6f46-764e126f12af.png)



## エディターユーティリティ
Editor utilities

以下のユーティリティは、エディタでのみ動作し、開発の生産性を向上させるのに役立ちます。


![133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/846db30a-106a-c6cc-f086-de62cd73c0ad.png)


## サービスインスペクタ
Service inspectors

サービス・インスペクタは、アクティブなサービスを表すシーン内オブジェクトを生成するエディタのみの機能です。これらのオブジェクトを選択すると、ドキュメントへのリンク、エディタの視覚化のコントロール、サービスの状態を把握するためのインスペクタが表示されます。

![40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/336bd391-9a13-8d91-fa07-867731e19ce5.png)


サービスインスペクタを有効にするには、設定プロファイルの「エディタの設定」で「サービスインスペクタを使用」をチェックします。

## 深度バッファレンダラ
Depth buffer renderer

一部の複合現実感プラットフォームで深度バッファを共有すると、ホログラムの安定性が向上します。例えば、Windows Mixed Realityプラットフォームでは、フレームのレンダリングにかかる時間内に頭の微妙な動きを考慮して、ピクセルごとにレンダリングシーンを修正することができます。しかし、これらの技術には、ジオメトリがユーザーからどこにどれだけ離れているかを知るための正確なデータを持つデプスバッファが必要です。

シーンがデプスバッファーに必要なすべてのデータを確実にレンダリングするために、開発者は設定プロファイルの「Editor Settings」にある「Render Depth Buffer」機能を切り替えることができます。これにより、現在のデプスバッファを取得し、ポストプロセスエフェクトであるDepthBufferRendererをメインカメラに適用することで、シーンビューにカラーとしてレンダリングされます。

![163.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4e16b668-2b77-f6ea-e386-2b03c71684c0.png)

Render Depth Buffer Utility シーンの青い円柱は、ZWriteをオフにしたマテリアルを使用しているため、深度データは書き込まれない

## ランタイムでのプロファイル変更
Changing profiles at runtime

ランタイムにプロファイルを更新することは可能ですが、一般的には2つの異なるシナリオとタイミングでこれが役に立ちます。

- MRTK初期化前のプロファイル切り替え。起動時、MRTKが初期化されてプロファイルがアクティブになる前に、まだ使用していないプロファイルを置き換えて、デバイスの機能に応じてさまざまな機能を有効/無効にします。例えば、空間マッピングハードウェアを持たないVRで体験を実行する場合、空間マッピングコンポーネントを有効にすることはおそらく意味がありません。
- アクティブプロファイルの切り替え。起動後、MRTKが初期化され、プロファイルがアクティブになった後、現在使用しているプロファイルを交換して、特定の機能の動作方法を変更する。例えば、アプリケーション内の特定のサブエクスペリエンスでは、ファーハンドポインターを完全に削除したい場合がある。

## MRTK初期化前のプロファイル切り替え
Pre MRTK initialization profile switch

これは、MRTKの初期化（すなわちAwake()）の前に実行されるMonoBehaviour（以下の例）をアタッチすることで実現できます。スクリプト（すなわちSetProfileBeforeInitializationへの呼び出し）はMixedRealityToolkitスクリプトよりも早く実行されなければならないことに注意してください。

```C#
using Microsoft.MixedReality.Toolkit;
using UnityEngine;

/// <summary>
///サンプルのMonoBehaviourは、MixedRealityToolkitオブジェクトの前に実行され、
///MRTKが初期化されたときに、シーンに保存されているプロファイルではなく、
///以下に指定されたプロファイルを使用するように、プロファイルを変更します。
/// </summary>
/// <remarks>
/// このスクリプトは、MixedRealityToolkit.csと比較して、スクリプト実行順序の中で高い優先順位を持たなければならないことに注意してください。スクリプトの実行順序の詳細については、https://docs.unity3d.com/Manual/class-MonoManager.html を参照してください。
/// </remarks>
public class PreInitProfileSwapper : MonoBehaviour
{

    [SerializeField]
    private MixedRealityToolkitConfigurationProfile profileToUse = null;

    private void Awake()
    {
        /// ここでは任意のMixedRealityToolkitConfigurationProfileを選択することができます
        ///（例えば、どのプロファイルをロードするかを決定するために、ここにいくつかの
        ///プラットフォーム・チェック・コードを追加することができます）。
        MixedRealityToolkit.SetProfileBeforeInitialization(profileToUse);
    }
}
```

profileToUseの代わりに、特定のプラットフォームに適用される任意のプロファイルのセットを持つことができます（例えば、HoloLens 1用、VR用、HoloLens 2用など）。また、他の様々な指標（例えば、https://docs.unity3d.com/ScriptReference/SystemInfo.html、カメラが不透明/透明かどうか）を使用して、どのプロファイルをロードするかを把握することも可能です。

## アクティブ・プロファイル・スイッチ
Active profile switch

これは、MixedRealityToolkit.Instance.ActiveProfileプロパティを、アクティブなプロファイルを置き換える新しいプロファイルに設定することで実現できます。

```C#
MixedRealityToolkit.Instance.ActiveProfile = profileToUse;
```

ランタイム中にActiveProfileを設定する場合、現在実行中のサービスの破壊は、すべてのサービスの最後のLateUpdate()の後に起こり、新しいプロファイルに関連するサービスのインスタンス化と初期化は、すべてのサービスの最初のUpdate()の前に起こることに注意してください。

このプロセスでは、アプリケーションに顕著な遅延が発生することがあります。また、MixedRealityToolkitスクリプトよりも高い優先度を持つスクリプトは、新しいプロファイルが正しくセットアップされる前に、そのアップデートを開始することができます。スクリプトの優先順位の詳細については、「スクリプト実行順序の設定」を参照してください。

プロファイルの切り替えプロセスでは、既存のUIカメラは変更されず、キャンバスを必要とするUnityのUIコンポーネントが切り替え後も動作するようになります。

# ハンド トラッキング(Ultraleap)

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/supported-devices/leap-motion-mrtk?view=mrtkunity-2021-01

# UI Controls

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7e26828a-1e53-c05b-de70-c2e22460fd3a.png)

# Button

![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/345f6370-5e72-10ac-1487-9c6a8abca45d.png)


ボタンは、ユーザーがすぐにアクションを起こすための手段となります。ボタンはMRの最も基本的なコンポーネントの一つです。MRTKでは、様々なタイプのボタンプレハブを提供しています。

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/ux-building-blocks/button?view=mrtkunity-2021-01

**MRTKのボタンプレハブ**
MRTK/SDK/Features/UX/Interactable/Prefabsフォルダ内のボタンプレハブの例

**Unity UI Image/Graphicベースのボタン**
- UnityUIInteractableButton.prefab
- PressableButtonUnityUI.prefab
- PressableButtonUnityUICircular.prefab
- PressableButtonHoloLens2UnityUI.prefab

**コライダーベースのボタン**
![MRTKbutton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a76c6d48-b0b7-d650-7580-a7682aefeeec.png)



ボタン(Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/Button.prefab)は、Interactableのコンセプトに基づいており、ボタンやその他のタイプのインタラクティブな表面のための簡単なUIコントロールを提供します。

▼Interactable

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2bd04f6f-4086-a1c0-df52-a8ce696e1c84.png)


基本的なボタンは、近距離でのインタラクションのための多関節ハンド入力や、遠距離でのインタラクションのための視線＋エアタップなど、利用可能なすべての入力方法をサポートしています。また、音声コマンドを使ってボタンをトリガーすることもできます。

PressableButtonHoloLens2（Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/PressableButtonHoloLens2.prefab）は、HoloLens 2のシェルスタイルのボタンで、ハンドトラッキングによる直接入力のためのボタンの正確な動きをサポートしています。InteractableスクリプトとPressableButtonスクリプトを組み合わせています。

HoloLens2では、不透明なバックプレートのボタンを使用することが推奨されます。透明なボタンは、以下のような操作性や安定性の問題があるため、お勧めできません。

- アイコンとテキストが物理的な環境に合わせて読みにくくなる
- イベントがいつ発生するのかがわかりにくい
- 透明な平面を通して表示されるホログラムは、HoloLens 2のDepth LSRスタビライゼーションでは不安定になる可能性があります

![175.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8b9585be-d2f7-6d51-4c0b-5afd7827ecbf.png)

## pressable buttonsの使い方

**Unity UIベースのボタン**

シーンにCanvasを作成します（GameObject -> UI -> Canvas）。CanvasのInspectorパネルで

- **Convert to MRTK Canvas** をクリックします。
- **Add NearInteractionTouchableUnityUI** をクリックします。
- Rect TransformコンポーネントのX,Y,Zスケールを0.001に設定します。

次に、以下の３つのうちどれかをCanvasにドラッグします。
- **PressableButtonUnityUI**（Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/PressableButtonUnityUI.prefab）
- **PressableButtonUnityUICircular**（Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/PressableButtonUnityUICircular.prefab）
- **PressableButtonHoloLens2UnityUI**（Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/PressableButtonHoloLens2UnityUI.prefab）

**コライダーベースのボタン**

以下の２つのうちどれかををシーンにドラッグします。
- **PressableButtonHoloLens2**  (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/PressableButtonHoloLens2.prefab)
- **PressableButtonHoloLens2Unplated** (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/PressableButtonHoloLens2Unplated.prefab)

これらのボタンプレハブは、手の入力や視線など、様々なタイプの入力に対するオーディオ・ビジュアル・フィードバックを持つようにすでに設定されています。

また、プレハブ自体やInteractableコンポーネントで公開されているイベントを利用して、追加のアクションを起こすことができます。
HandInteractionExampleシーンの押下可能なボタンは、InteractableのOnClickイベントを使用して、立方体の色の変化をトリガーしています。このイベントは、視線、エアタップ、ハンドレイなどのさまざまなタイプの入力方法や、pressable buttonスクリプトによる物理的なボタンの押下などでトリガーされます。

![55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a14aa714-fac8-f3c7-7d50-a84671c7c715.png)


Pressable ボタンがいつ OnClick イベントを発生させるかは、ボタンの PhysicalPressEventRouter を通じて設定できます。たとえば、Interactable On Click を Event On Press に設定することで、ボタンが押されて離されるのではなく、最初に押されたときに OnClick が発生するように設定できます。

![103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e6891d8e-9346-634e-03b1-b4593348e797.png)


特定の関節の手の入力状態の情報を利用するには、pressable buttonsイベント（Touch Begin、Touch End、Button Pressed、Button Released）を使用します。ただし、これらのイベントは、エアタップ、ハンドレイ、視線の入力には反応しません。近くにいる人と遠くにいる人の両方のインタラクションをサポートするには、InteractableのOnClickイベントを使用することをお勧めします。

![126.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/63c652a8-6a53-77d5-ebc0-7137e0a6e04a.png)

**インタラクションの状態**

アイドル状態では、ボタンの前面プレートは見えません。指が近づいたり、視線入力のカーソルが表面をターゲットにすると、フロントプレートの光る境界線が見えるようになります。さらに、フロントプレート表面の指先の位置がハイライトされます。指で押すと、指先の動きに合わせて前面板が動きます。指先が前面プレートの表面に触れると、微妙なパルス効果が表示され、タッチポイントの視覚的なフィードバックが得られます。

HoloLens2のシェル型ボタンには、ユーザーのインタラクションに対する信頼感を高めるための視覚的な手がかりやアフォーダンスが数多く用意されています。

![251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/21593095-0576-48bc-b183-fbe61f810de2.png)

インタラクションの状態
近接照明 フォーカスハイライト ケージの圧縮 トリガー時のパルス
近接照明 フォーカスハイライト ケージの圧縮 トリガー時のパルス
微妙なパルス効果は、押すことのできるボタンによって引き起こされます。ボタンは、現在インタラクションしているポインター上に存在する近接ライトを探します。近接ライトが見つかると、ProximityLight.Pulseメソッドが呼び出され、シェーダーのパラメータを自動的にアニメーションさせてパルスを表示します。

**インスペクタのプロパティ**

![62.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/b7d01d74-1c5a-76e6-cb30-269b7ae43f48.png)


- Box Collider: ボタンのフロントプレート用のボックスコライダです。
- Pressable Button: 手で押すインタラクションによるボタンの動きのロジックです。
- Physical Press Event Router: 手で押すインタラクションのイベントをInteractableに送るスクリプトです。
- Interactable: Interactableは様々な種類のインタラクションの状態やイベントを扱います。HoloLensの視線、ジェスチャー、音声入力や、没入型ヘッドセットのモーションコントローラーの入力は、このスクリプトで直接処理されます。
- Audio Source: オーディオフィードバッククリップ用のUnityオーディオソースです。

NearInteractionTouchable.cs アーティキュレートされた手の入力で任意のオブジェクトをタッチ可能にするために必要です。



**プレハブのレイアウト**

ButtonContentオブジェクトには、フロントプレート、テキストラベル、アイコンが含まれています。FrontPlate は、Button_Box シェーダを使用して人差し指の近さに反応します。フロントプレートは、Button_Boxシェーダを使用して、人差し指の接近に反応し、光る境界線、近接光、タッチ時のパルス効果を示します。テキストラベルはTextMesh Proで作られています。SeeItSayItLabelの可視性は、Interactableのテーマによって制御されます。

![136.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/61c445ae-7811-adf4-59ef-9d6852c13555.png)


**アイコンとテキストの変更方法**

MRTKのボタンはButtonConfigHelperというコンポーネントを使って、ボタンのアイコンやテキスト、ラベルを変更できるようになっています。(選択されたボタンに要素が存在しない場合、いくつかのフィールドが存在しない可能性があることに注意してください)。

![29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2dc4bf7f-abee-79aa-318d-a5d5cf4d6b65.png)


**アイコンセットの作成と変更**

アイコンセットとは、ButtonConfigHelperコンポーネントが使用するアイコン資産の共有セットです。3 種類のアイコンスタイルがサポートされています。

- Quadアイコンは、MeshRenderer を使用してクワッド上にレンダリングされます。これはデフォルトのアイコン・スタイルです。
- Spriteアイコンは、SpriteRenderer を使用してレンダリングされます。このスタイルは、アイコンをスプライトシートとしてインポートしたい場合や、アイコンのアセットをUnity UIコンポーネントと共有したい場合に便利です。このスタイルを使用するには、Sprite Editorパッケージをインストールする必要があります（Windows -> Package Manager -> 2D Sprite）。
- CharアイコンはTextMeshProコンポーネントを使ってレンダリングされます。これは、アイコンのフォントを使用したい場合に便利です。HoloLensのアイコンフォントを使用するには、TextMeshProのフォントアセットを作成する必要があります。

ボタンが使用するスタイルを変更するには、ButtonConfigHelperのIconsドロップダウンを展開し、Icon Styleドロップダウンから選択します。

アセットメニューで新しいボタンアイコンセットを作成することができます。
Create > Mixed Reality Toolkit > Icon Set

クアッドとスプライトのアイコンを追加するには、それぞれの配列にドラッグします。Charアイコンを追加するには、まずフォントアセットを作成して割り当てる必要があります。

MRTK 2.4以降では、カスタムアイコンのテクスチャをIconSetに移動することをお勧めします。
プロジェクト内のすべてのボタンのアセットを新しい推奨フォーマットにアップグレードするには、ButtonConfigHelperMigrationHandlerを使用します。
(Mixed Reality Toolkit -> Utilities -> Migration Window -> Migration Handler Selection -> Microsoft.MixedReality.Toolkit.Utilities.ButtonConfigHelperMigrationHandler)

ボタンのアップグレードに必要なMicrosoft.MixedRealityToolkit.Unity.Toolsパッケージをインポートします。


![75.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4933e43a-97ad-35e6-500a-e55bdf3a9e73.png)


移行中にデフォルトアイコンセットにアイコンが見つからない場合、カスタムアイコンセットがMixedRealityToolkit.Generated/CustomIconSetsに作成されます。これが行われたことを示すダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/3c303983-3e11-1b96-fcc4-55ad247ac586.png)

## HoloLensのアイコンフォントアセットの作成

まず、アイコンフォントをUnityにインポートします。Windowsマシンでは、Windows/Fonts/holomdl2.ttfにデフォルトのHoloLensフォントがあります。このファイルをコピーしてAssetsフォルダに貼り付けます。

次に、「Window」→「TextMeshPro」→「Font Asset Creator」でTextMeshPro Font Asset Creatorを開きます。以下は、HoloLensのフォントアトラスを生成するための推奨設定です。すべてのアイコンを含めるには、以下のUnicode範囲をCharacter Sequenceフィールドに貼り付けます。

```c#
E700-E702,E706,E70D-E70E,E710-E714,E718,E71A,E71D-E71E,E720,E722,E728,E72A-E72E,E736,E738,E73F,E74A-E74B,E74D,E74F-E752,E760-E761,E765,E767-E769,E76B-E76C,E770,E772,E774,E777,E779-E77B,E782-E783,E785-E786,E799,E7A9-E7AB,E7AF-E7B1,E7B4,E7C8,E7E8-E7E9,E7FC,E80F,E821,E83F,E850-E859,E872-E874,E894-E895,E8A7,E8B2,E8B7,E8B9,E8D5,E8EC,E8FB,E909,E91B,E92C,E942,E95B,E992-E995,E9E9-E9EA,EA37,EA40,EA4A,EA55,EA96,EB51-EB52,EB65,EB9D-EBB5,EBCB-EBCC,EBCF-EBD3,EC03,EC19,EC3F,EC7A,EC8E-EC98,ECA2,ECD8-ECDA,ECE0,ECE7-ECEB,ED17,EE93,EFA9,F114-F120,F132,F181,F183-F186
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c0499b08-e28e-ce38-b5c7-4cf8af7eb725.png)

フォントアセットが生成されたら、それをプロジェクトに保存して、Icon SetのChar Icon Fontフィールドに割り当てます。Available Icons」ドロップダウンには、アイコンが表示されます。アイコンをボタンで使用できるようにするには、アイコンをクリックします。選択されたアイコン」ドロップダウンに追加され、ButtonConfigHelper に表示されるようになります。オプションで、アイコンにタグを与えることができます。これにより、実行時にアイコンを設定することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/474b7092-25be-7a80-2ebe-33e4b764eef1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/53776536-f32e-dad4-3aaf-5ee9f54459ac.png)


```c#
public void SetButtonToAdjust()
{
    ButtonConfigHelper buttonConfigHelper = gameObject.GetComponent<ButtonConfigHelper>();
    buttonConfigHelper.SetCharIconByName("AppBarAdjust");
}
```

作成したアイコンセットを使用するには、ボタンを選択し、**ButtonConfigHelper** の Icons ドロップダウンを展開して、Icon Set フィールドに割り当てます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2a3ea73d-8f50-7c83-92e2-f081d59c8629.png)

**ボタンのサイズを変更する方法**

HoloLens 2のシェル型ボタンのサイズは32x32mmです。この寸法をカスタマイズするには、ボタンのプレハブでこれらのオブジェクトのサイズを変更します。

1. FrontPlate
2. BackPlateの下のQuad
3. ルートのBox Collider

次に、ボタンのルートにあるNearInteractionTouchableスクリプトの**Fix Bounds**ボタンをクリックします。

FrontPlateボタンのサイズを更新する 

![48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/b7345187-036a-21af-0a2a-6d74feecae5c.png)


Quadボタンのサイズのカスタマイズを更新する

![160.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/19e34ed9-3092-e445-d0d0-85af2fcdf057.png)

Box Collider ボタンのサイズを更新する

![189.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/b0fef067-7809-bab0-7f0f-69d2439b0624.png)


'Fix Bounds'をクリックする

![152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/60c96550-b046-ac8c-7e6e-c3535760ea03.png)

## 音声コマンド ('see-it, say-it')

Speech Input Handler(音声入力ハンドラ) Pressable ButtonのInteractableスクリプトは、すでに **IMixedRealitySpeechHandler** を実装しています。ここに音声コマンドのキーワードを設定することができます。


![124.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/be11b2b6-439c-259c-51aa-d80de64b36d4.png)


**Speech Input Profile** さらに、音声コマンドキーワードをグローバルな **Speech Commands Profile** に登録する必要があります。

![218.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9be69aa1-17a1-ae10-4b98-90bcbd12e286.png)



See-it, Say-itラベル 押せるボタンのプレハブには、SeeItSayItLabelオブジェクトの下に、プレースホルダーのTextMesh Proラベルがあります。このラベルを使って、ボタンの音声コマンドキーワードをユーザーに伝えることができます。


![224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c0bf9d16-d6f1-5b1f-71a2-aa435ec0ea0e.png)


## ボタンを一から作る方法

PressableButton Exampleシーンでは、これらのボタンの例を見ることができます。


![157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9da0621f-9f0b-c0a1-b20d-5fffc65e3405.png)


**1.キューブを使った押下可能なボタンの作成（近接インタラクションのみ**

1. UnityのCubeを作成する（GameObject > 3D Object > Cube）
2. **PressableButton.cs**スクリプトの追加
3. **NearInteractionTouchable.cs**スクリプトの追加

PressableButtonのInspectorパネルで、**Moving Button Visuals**に cubeオブジェクトを割り当てます。


![71.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/23cb4e32-b01e-58bf-6d45-e8072329df66.png)



キューブを選択すると、オブジェクトに複数のカラーレイヤーが表示されます。これは、「プレス設定」の距離の値を視覚化したものです。ハンドルを使って、いつプレスを開始するか（オブジェクトを動かすか）、いつイベントをトリガーするかを設定できます。


![28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/eba3e664-d2d7-8c38-c248-3d1d8158854b.png)

![100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/ab082b38-9137-4b75-2f11-8613d7563a7c.png)

ボタンを押すと、ボタンが動き、PressableButton.cs スクリプトで公開されている TouchBegin(), TouchEnd(), ButtonPressed(), ButtonReleased() などの適切なイベントが生成されます。


![252.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/227da6d9-6ed9-11e8-7864-26301d54e678.png)

**トラブルシューティング**

ボタンが二重に押されてしまう場合は、Enforce Front Push プロパティが有効で、Start Push Distance プレーンが Near Interaction Touchable プレーンの前に配置されていることを確認してください。Near Interaction Touchable プレーンは、下図の白い矢印の原点の前に置かれた青いプレーンで示されています。

![166.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2973e59c-7f0d-3554-97a2-c1da2931f9e0.png)

![227.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/47d5a089-ebd2-7bb8-db26-5a5059b16895.png)



**2.基本的な立方体ボタンに視覚的なフィードバックを加える**

MRTK Standard Shaderには、ビジュアルフィードバックを簡単に追加するための様々な機能が用意されています。マテリアルを作成し、シェーダーMixed Reality Toolkit/Standardを選択します。または、/SDK/StandardAssets/Materials/にある、MRTK Standard Shaderを使用した既存のマテリアルの1つを使用または複製します。

![210.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8f8f8ddb-bca0-0c95-c546-5f755278e0f5.png)

**Fluent Options** の「Hover Light」と「Proximity Light」をチェックします。これにより、near hand(Proximity Light)とfar pointer(Hover Light)の両方のインタラクションに対するビジュアルフィードバックが有効になります。



![115.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/67e2a87b-fa3a-f858-c02e-f8e64d70bfc9.png)


![67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/411cbc12-c9a4-e44d-49ac-58ae74f4e4f8.png)

**3.基本的なキューブボタンにオーディオフィードバックを追加する**

PressableButton.csスクリプトはTouchBegin()、TouchEnd()、ButtonPressed()、ButtonReleased()などのイベントを公開しているので、簡単にオーディオフィードバックを割り当てることができます。UnityのAudio Sourceをキューブオブジェクトに追加し、AudioSource.PlayOneShot()を選択してオーディオクリップを割り当てるだけです。SDK/StandardAssets/Audio/フォルダにあるMERTK_Select_MainとMERTK_Select_Secondaryのオーディオクリップを使うことができます。


![244.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/bf1dd750-c069-9408-b3d4-7e7731b52f20.png)


![127.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/adc38d66-1dca-28a3-1277-7f357de250ac.png)

**4.ビジュアル・ステートの追加とファー・インタラクション・イベントの処理**

Interactableは、さまざまなタイプの入力インタラクションに対応したビジュアルステートを簡単に作成するためのスクリプトです。また、ファー・インタラクション・イベントも処理します。Interactable.cs を追加し、キューブ・オブジェクトを [Profiles] の [Target] フィールドにドラッグ・アンド・ドロップします。次に、ScaleOffsetColorTheme というタイプの新しいテーマを作成します。このテーマでは、「Focus」や「Pressed」などの特定のインタラクション状態におけるオブジェクトの色を指定できます。また、ScaleとOffsetも同様にコントロールできます。イージングにチェックを入れ、継続時間を設定すると、視覚的な移行がスムーズになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8d4ccd74-5895-c05e-682d-1c3769b6d60a.png)



遠くのインタラクション（ハンドレイやゲイズカーソル）と近くのインタラクション（手）の両方にオブジェクトが反応するのがわかります。

![112.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/cbf06ca9-5ba2-30c9-e6df-03a6a95922ff.png)

![39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/809b3376-3fa7-3ad6-c3ee-45a959095909.png)

**カスタムボタンの例**

HandInteractionExampleシーンでは、PressableButtonを使用したピアノボタンと丸いボタンの例をご覧いただけます。


![197.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f3d0cf77-729b-acae-02ab-4f15c50f7426.png)


![209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/45fa084e-d2ef-d41b-5b3b-858c42c1e4ee.png)

各ピアノキーにはPressableButtonとNearInteractionTouchableスクリプトが割り当てられています。ここで重要なのは、NearInteractionTouchableのLocal Forward方向が正しいかどうかを確認することです。エディタでは白い矢印で表示されています。この矢印がボタンの前面から離れていることを確認してください。


![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5f12d054-db20-4880-9e26-e9e192393e1a.png)


# Boundsコントロール

![201.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a725b82a-4bfe-b9bf-6b21-2f03bbcc9b74.png)


BoundsControlは、従来のBoundingBoxにあった操作のための新しいコンポーネントです。
Bounds controlでは、セットアップの改善と簡素化が行われ、新しい機能が追加されています。
このコンポーネントは、非推奨となるバウンディング・ボックスの代わりとなるものです。

**BoundsControl.cs**スクリプトは、mixed realityの中でオブジェクトを変換するための基本的な機能を提供します。bounds controlは、ホログラムの周りにボックスを表示して、それがインタラクティブに操作できることを示します。
ボックスの角や端にあるハンドルで、オブジェクトの拡大縮小、回転、平行移動ができます。また、バウンズコントロールは、ユーザーの入力にも反応します。例えば、HoloLens2では、バウンズコントロールが指の接近に反応し、オブジェクトとの距離を認識しやすくするためのビジュアルフィードバックを提供します。すべてのインタラクションとビジュアルは簡単にカスタマイズできます。

**シーン例**

BoundsControlExamplesシーンでは、bounds controlの設定例を見ることができます。

![188.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/df8bc260-0994-4b05-86be-209b3c6c3c83.png)

### Inspectorのプロパティ

**Target object**

このプロパティは、どのオブジェクトがバウンズコントロールの操作によって変換されるかを指定します。オブジェクトが設定されていない場合は、デフォルトでオーナーオブジェクトが設定されます。

**Activation behavior（起動時の動作）**

bounds controlインターフェイスの起動にはいくつかのオプションがあります。

- Activate On Start: シーンが開始されるとバウンズコントロールが表示されます。
- Activate By Proximity: 近接で起動。Bounds Controlは、アーティキュレートされた手がオブジェクトに近づいたときに表示されます。
- Activate By Pointer: ポインタで起動します。バウンズコントロールは、ハンドレイポインターでターゲットされたときに表示されるようになります。
- 近接とポインターで起動する: ハンドレイ・ポインターでターゲットされるか、関節ハンドが対象物に近づくと、バウンズコントロールが見えるようになります。
- 手動で起動する。バウンズコントロールは自動的には表示されません。boundsControl.Activeプロパティにアクセスすることで、スクリプトを使って手動でアクティブにすることができます。


**Bounds オーバーライド**

バウンズ計算のために、オブジェクトからボックス コライダを設定します。

**ボックス パディング**

コントロールのエクステントの計算に使用されるコライダのバウンドにパディングを追加します。これは、インタラクションだけでなく、ビジュアルにも影響します。

**軸のフラット化**

コントロールのいずれかの軸をフラットにして2次元化し、その軸に沿った操作を禁止するかどうかを示します。この機能は、スレートのような薄いオブジェクトに使用できます。軸を平らにする］が［自動］に設定されている場合、スクリプトは自動的に最小の範囲の軸を平らにする軸として選択します。

**スムージング**

スムージングセクションでは、コントロールのスケールと回転に対するスムージングの動作を設定できます。

**ビジュアル**

バウンドコントロールの外観は、対応するビジュアル設定のいずれかを変更することで設定できます。ビジュアル設定は、リンクされた、またはインライン化されたスクリプト可能なオブジェクトで、詳細は設定オブジェクトのセクションで説明されています。

**設定オブジェクト**

コントロールには、スクリプト可能なオブジェクトとして保存され、異なるインスタンスやプレハブ間で共有できる設定オブジェクトのセットが付属しています。設定は、個々のスクリプト可能なアセットファイルとして、またはプレハブ内のネストされたスクリプト可能なアセットとして、共有およびリンクすることができます。また、外部またはネストされたスクリプト可能なアセットにリンクすることなく、インスタンス上で直接設定を定義することもできます。

設定が現在のインスタンスの一部として共有されているかインライン化されているかは、バウンドコントロールインスペクタのプロパティインスペクタにメッセージが表示されます。さらに、共有されたインスタンスは、バウンズコントロールのプロパティウィンドウ自体では直接編集できませんが、代わりにリンク先のアセットを直接変更して、共有されたコンフィグレーションに誤って変更が加えられないようにする必要があります。

現在、バウンズコントロールは以下の機能のコンフィギュレーションオブジェクトのオプションを提供しています。

- Handles
    - Scale handles
    - Rotation handles
    - Translation handles
- Links / Wireframe
- Box display
- Proximity effect

**Box configuration(ボックス構成)**

ボックス設定は、コライダのサイズとボックスのパディングで定義された境界を持つソリッドボックスのレンダリングを担当します。以下のプロパティを設定できます。

- Box material：インタラクションが発生していないときにレンダリングされるボックスに適用されるマテリアルを定義します。このマテリアルが設定されている場合のみ、ボックスがレンダリングされます。
- Box grabbed material：ユーザーがコントロールをニアまたはファーのインタラクションで掴んだときのボックスのマテリアル。
- Flatten axis display scale: 軸の 1 つがフラット化された場合にボックスの表示に適用されるスケールです。

**Scale handles configuration(スケールハンドルの設定)**

このプロパティドロワーでは、バウンドコントロールのスケールハンドルの動作と表示を変更できます。

- Handle material：ハンドルに適用されるマテリアルです。
- Handle grabbed material: 掴まれたハンドルに適用されるマテリアルです。
- Handle prefab: スケールハンドルのオプションのプレハブ。nonが設定されている場合、MRTKはデフォルトで立方体を使用します。
- Handle size: スケールハンドルのサイズ。
- Collider padding: ハンドルのコライダに追加するパディングです。
- Draw tether when manipulating: アクティブな場合、インタラクションの開始点から現在の手またはポインタの位置までテザーラインを描きます。
- Handles ignore collider(ハンドルがコライダを無視)：ここにコライダがリンクされている場合、ハンドルはこのコライダとのコリジョンを無視します。
- Handle slate prefab: コントロールがフラット化されたときにハンドルに使用するプレハブです。
- Show scale handles：ハンドルの可視性をコントロールします。
- Scale behavior(スケール動作)：均一または非均一なスケールに設定できます。

**Rotation handles configuration(回転ハンドル設定)**

この設定では、回転ハンドルの動作を定義します。

- Handle material：ハンドルに適用されるマテリアルです。
- Handle grabbed material: 掴まれたハンドルに適用されるマテリアル。
- Handle prefab: ハンドルのオプションのプレハブ。nonが設定されている場合、MRTKはデフォルトで球体を使用します。
- Handle size: ハンドルのサイズ。
- Collider padding: ハンドルのコライダに追加するパディングです。
- Draw tether when manipulating: アクティブな場合、インタラクションの開始点から現在の手またはポインタの位置までテザーラインを描きます。
- Handles ignore collider：ここにコライダがリンクされている場合、ハンドルはこのコライダとのコリジョンを無視します。
- Handle prefab collider type: 作成されたハンドルで使用されるコライダタイプです。
- Show handle for X：X軸用のハンドルの可視性をコントロールします。
- Show handle for Y：Y軸用のハンドルの可視性をコントロールします。
- Show handle for Z：Z軸用のハンドルの可視性をコントロールします。

**Translation handles configuration(トランスレーションハンドルの設定)**

バウンドコントロールのためのトランスレーションハンドルの有効化と設定を行います。デフォルトでは、トランスレーション・ハンドルは無効になっています。

- Handle material: ハンドルに適用されるマテリアルです。
- Handle grabbed material: 掴まれたハンドルに適用されるマテリアルです。
- Handle prefab: オプションでハンドルのprefabを設定します。nonが設定されている場合、MRTKはデフォルトで球体を使用します。
- Handle size: ハンドルのサイズ。
- Collider padding: ハンドルのコライダに追加するパディングです。
- Draw tether when manipulating: アクティブな場合、インタラクションの開始点から現在の手またはポインタの位置までテザーラインを描きます。
- Handles ignore collider：ここにコライダがリンクされている場合、ハンドルはこのコライダとのコリジョンを無視します。
- Handle prefab collider type: 作成されたハンドルで使用されるコライダタイプです。
- Show handle for X：X軸用のハンドルの可視性をコントロールします。
- Show handle for Y：Y軸用のハンドルの可視性をコントロールします。
- Show handle for Z：Z軸用のハンドルの表示をコントロールします。

**リンク設定（ワイヤーフレーム)**

リンク設定は、バウンズコントロールのワイヤーフレーム機能を有効にします。設定できるプロパティは以下の通りです。

- Wireframe material：ワイヤーフレームのメッシュに適用されるマテリアルを指定します。
- Wireframe edge radius（ワイヤーフレームのエッジ半径）：ワイヤーフレームの太さです。
- Wireframe shape：ワイヤーフレームの形状は立方体または円筒体のいずれかです。
- Show wireframe：ワイヤフレームの表示をコントロールします。


**Proximity effect configuration(近接効果の設定)**

手との距離に応じたアニメーションでハンドルを表示／非表示します。2段階のスケーリングアニメーションを備えています。デフォルトでは、HoloLens 2 スタイルの動作に設定されています。
 

![43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0d009922-e7ea-ae33-b6d4-a41004ca8952.png)

- Proximity Effect Active (近接効果 アクティブ):近接ベースのハンドル起動を有効にする
- Object Medium Proximity (オブジェクト 中距離近接): 1段階目のスケーリングのための距離
- Object Close Proximity (オブジェクト 近接): 2段階目のスケーリングのための距離
- Far Scale (遠いスケール): 手がバウンドコントロールインタラクションの範囲外にあるときのハンドルアセットのデフォルトスケール値（上記の「ハンドル中近」で定義された距離。デフォルトでハンドルを隠すには0を使用する)
- Medium Scale（中程度のスケール）:手がバウンズコントロールインタラクションの範囲内にあるときのハンドルアセットのスケール値（'Handle Close Proximity'によって上記で定義された距離。通常のサイズを表示するには1を使用します)
- Close Scale(近いスケール):手がグラブ操作の範囲内にあるときのハンドルアセットのスケール値（「ハンドルの近さ」で上記のように定義される距離。大きなサイズを表示するには1.xを使用してください)
- Far Grow Rate(遠くの成長率): 近接スケールのオブジェクトが、手が中距離から遠距離に移動したときにスケールする割合。
- Medium Grow Rate(中距離の成長率): 中距離から近距離に移動したときの、近接スケールのオブジェクトのレートです。
- Close Grow Rate（近接成長率）: 手が近距離からオブジェクトの中心に移動したときに、近接スケールのオブジェクトがスケールする割合。

**Constraint System(制約システム)**

バウンズコントロールは、バウンズコントロールのハンドルを使用しているときに、移動、回転、またはスケーリングの動作を制限または変更するための制約マネージャの使用をサポートしています。

プロパティインスペクタでは、同じゲームオブジェクトに接続されている利用可能なすべての制約マネージャがドロップダウンで表示され、選択した制約マネージャをスクロールしてハイライトするオプションがあります。


![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f1191562-10b1-7476-56e7-349c2a99e1cd.png)

**イベント**
Boundsコントロールには以下のイベントがあります。この例では、これらのイベントを使用して音声フィードバックを再生します。

Rotate Started: 回転が開始されたときに実行します。
Rotate Stopped：回転が停止したときに実行します。
Scale Started：スケーリングが開始されたときに実行します。
Scale Stopped：スケーリングが停止したときに実行されます。
Translate Started: 移動が開始されたときに実行します。
Translate Stopped: 移動が停止したときに実行します。

![261.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/302cd338-d9e9-1618-1e56-682398615296.png)


**Elastics (実験段階)**

elastics（エラスティック）は、境界制御でオブジェクトを操作する際に使用できます。ただし、elasticsはまだ実験段階です。elasticsを有効にするには、既存のelasticsマネージャーコンポーネントをリンクするか、「Add Elastics Manager」ボタンで新しいelasticsマネージャーを作成してリンクします。


![180.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/65370a0e-3f5b-361b-5091-ad29f4a5a8c0.png)




**Handle styles(ハンドルスタイル)**

デフォルトでは、BoundsControl.csスクリプトを割り当てただけでは、HoloLens 1st genスタイルのハンドルが表示されます。HoloLens 2スタイルのハンドルを使用するには、適切なハンドルプレファブとマテリアルを割り当てる必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4babb1ac-2fd3-44ac-db3b-136cb86c181a.png)


以下は、HoloLens 2スタイルのバウンドコントロールハンドルのプレハブ、マテリアル、およびスケーリング値です。この例は、BoundsControlExamplesシーンでご覧いただけます。

![53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c37775fe-d12d-cd97-d7e1-a672a6be1d4d.png)

**ハンドル（HoloLens 2スタイルの設定)**

- Handle Material: BoundingBoxHandleWhite.mat
- Handle Grabbed Material: BoundingBoxHandleBlueGrabbed.mat
- Scale Handle Prefab: MRTK_BoundingBox_ScaleHandle.prefab
- Scale Handle Slate Prefab: MRTK_BoundingBox_ScaleHandle_Slate.prefab
- Scale Handle Size: 0.016 (1.6cm)
- Scale Handle Collider Padding: 0.016 (つかめるコライダをハンドルのビジュアルより少し大きくする)
- Rotation Handle Prefab: MRTK_BoundingBox_RotateHandle.prefab
- Rotation Handle Size: 0.016
- Rotation Handle Collider Padding: 0.016 (つかめるコライダをハンドルのビジュアルより少し大きくする)


**object manipulatorによるトランスフォームの変更**

bounds controlは、ObjectManipulator.cs と組み合わせて使用することで、ハンドルを使用せずに特定の種類の操作（例：オブジェクトの移動）を行うことができます。マニピュレーションハンドラは、片手と両手の両方のインタラクションをサポートします。ハンドトラッキングを使って、オブジェクトを近くで操作することができます。



![120.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/927d3693-a012-81a6-bfc3-12d60c0b6257.png)

ObjectManipulatorのファーインタラクションを使ってバウンズコントロールのエッジを動かしたときに同じように動作させるためには、上のスクリーンショットにあるように、On Manipulation Started / On Manipulation EndedのイベントをBoundsControl.HighlightWires / BoundsControl.UnhighlightWiresにそれぞれ接続することをお勧めします。

**Unity Inspectorを使ってbounds controlを追加・設定する方法**

1. オブジェクトにBox Colliderを追加する
2. BoundsControlスクリプトをオブジェクトに割り当てる
3. Activation'メソッドなどのオプションを設定する（後述のInspector propertiesセクションを参照
4. (オプション）HoloLens 2スタイルのバウンズコントロールにプレハブやマテリアルを割り当てます（下記の「ハンドルスタイル」セクションを参照）。


> 注意
> 
> インスペクタの「ターゲットオブジェクト」と「バウンズオーバーライド」フィールドを使って、複数の子コンポーネントを持つオブジェクトの特定のオブジェクトとコライダを割り当てます。

![262.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/545849dc-4b0f-e3b6-f30c-c4f6f748159b.png)


**バウンドコントロールをコードに追加・設定する方法**

1) キューブ型ゲームオブジェクトのインスタンス化

```c#
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
```

2) AddComponent<>()を使って、BoundsControlスクリプトをコライダ付きのオブジェクトに割り当てる。

```c#
private BoundsControl boundsControl;
boundsControl = cube.AddComponent<BoundsControl>();
```

3) オプションの構成は、コントロール上で直接行うか、スクリプト可能な構成のいずれかを介して行います (後述の「インスペクタのプロパティと構成」のセクションを参照)。

```c#
// アクティベーションメソッドの変更
boundsControl.BoundsControlActivation = BoundsControlActivationType.ActivateByProximityAndPointer;
// スケールハンドルを大きくする
boundsControl.ScaleHandlesConfig.HandleSize = 0.1f;
// X軸の回転ハンドルを隠す
boundsControl.RotationHandlesConfig.ShowRotationHandleForX = false;
```

4) (オプション）HoloLens 2スタイルのバウンズコントロールにプレハブとマテリアルを割り当てます。マテリアルとプレハブは動的にロードされる必要があるため、これにはインスペクタによる割り当てが必要です。



> 注意
> 
> Unityの「Resources」フォルダやShader.Findを使用してシェーダーを動的に読み込むことは、実行時にシェーダーのパーミュテーションが欠落する可能性があるため、推奨されません。


```c#
BoxDisplayConfiguration boxConfiguration = boundsControl.BoxDisplayConfig;
boxConfiguration.BoxMaterial = [Assign BoundingBox.mat]
boxConfiguration.BoxGrabbedMaterial = [Assign BoundingBoxGrabbed.mat]
ScaleHandlesConfiguration scaleHandleConfiguration = boundsControl.ScaleHandlesConfig;
scaleHandleConfiguration.HandleMaterial = [Assign BoundingBoxHandleWhite.mat]
scaleHandleConfiguration.HandleGrabbedMaterial = [Assign BoundingBoxHandleBlueGrabbed.mat]
scaleHandleConfiguration.HandlePrefab = [Assign MRTK_BoundingBox_ScaleHandle.prefab]
scaleHandleConfiguration.HandleSlatePrefab = [Assign MRTK_BoundingBox_ScaleHandle_Slate.prefab]
scaleHandleConfiguration.HandleSize = 0.016f;
scaleHandleConfiguration.ColliderPadding = 0.016f;
RotationHandlesConfiguration rotationHandleConfiguration = boundsControl.RotationHandlesConfig;
rotationHandleConfiguration.HandleMaterial = [Assign BoundingBoxHandleWhite.mat]
rotationHandleConfiguration.HandleGrabbedMaterial = [Assign BoundingBoxHandleBlueGrabbed.mat]
rotationHandleConfiguration.HandlePrefab = [Assign MRTK_BoundingBox_RotateHandle.prefab]
rotationHandleConfiguration.HandleSize = 0.016f;
rotationHandleConfiguration.ColliderPadding = 0.016f;
```


**例 MinMaxScaleConstraint を使用した最小、最大境界制御スケールの設定**

最小と最大のスケールを設定するには、コントロールにMinMaxScaleConstraintを取り付けます。バウンズコントロールは自動的に制約マネージャをアタッチしてアクティブにするので、MinMaxScaleConstraintがアタッチされて構成されると、トランスフォームの変更に自動的に適用されます。

また、MinMaxScaleConstraintを使用して、ObjectManipulatorの最小および最大スケールを設定することもできます。

```c#
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
bcontrol = cube.AddComponent<BoundsControl>();
// 重要：BoundsControlは、制約マネージャが存在しない場合、起動時に制約マネージャを作成します。
// 制約マネージャを手動でアタッチする必要はありません。
MinMaxScaleConstraint scaleConstraint = bcontrol.gameObject.AddComponent<MinMaxScaleConstraint>();
scaleConstraint.ScaleMinimum = 1f;
scaleConstraint.ScaleMaximum = 2f;
```

**例 ゲームオブジェクトの周囲にバウンズコントロールを追加する**

オブジェクトの周りにバウンズコントロールを追加するには、単純にBoundsControlコンポーネントを追加します。

```c#
private void PutABoundsControlAroundIt(GameObject target)
{
   target.AddComponent<BoundsControl>();
}
```

**バウンディングボックスからの移行**

バウンディングボックスを使用している既存のプレハブやインスタンスは、MRTKツールパッケージの一部であるマイグレーションウィンドウを使って、新しいバウンズコントロールにアップグレードすることができます。

また、バウンディングボックスの個々のインスタンスをアップグレードするには、コンポーネントのプロパティインスペクタにある移行オプションを使用します。


![113.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f0d751da-c26a-6878-d079-b82d79b45b38.png)


# Object manipulator（オブジェクトマニピュレーター）

![214.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/464ca8f6-26b3-e29c-3d0e-95f3b5899574.png)


**ObjectManipulator**は、これまで**ManipulationHandler**にあった操作動作のための新しいコンポーネントです。
**ObjectManipulator**は、多くの改良と簡素化がなされています。このコンポーネントは、廃止される予定の**ManipulationHandler**の代わりとなります。

**ObjectManipulator**スクリプトは、片手または両手を使って、オブジェクトを移動、拡大縮小、回転可能にします。**ObjectManipulator**は、さまざまな入力に対するオブジェクトの反応を制御するように設定できます。このスクリプトは、HoloLens2の多関節ハンド、HoloLens2のハンドレイ、HoloLens1の視線とジェスチャー、イマーシブヘッドセットのモーションコントローラの入力など、ほとんどの形式のインタラクションで動作するはずです。

[動画参照](https://sec.ch9.ms/ch9/a8d7/ff16f325-4d32-459f-8ae0-2d565962a8d7/ObjectManipulator_high.mp4)

**object manipulatorの使い方**

オブジェクトマニピュレーターを使うには、まずGameObjectに**ObjectManipulator**スクリプトコンポーネントを追加します。その際、オブジェクトのグラブ可能な範囲に合わせて、colliderも追加してください。

関節のある手の近くの入力にオブジェクトが反応するようにするには、**NearInteractionGrabbable**スクリプトも追加します。

オブジェクトにリジッドボディコンポーネントを追加することで、オブジェクトのマニピュレーターの物理挙動を有効にすることができます。このコンポーネントを追加することで有効になる物理動作については、「Physics and collisions」で詳しく説明しています。

また、マニピュレーションコンストレイントコンポーネントをオブジェクトに追加することで、マニピュレーションを制約することができます。これらのコンポーネントは、マニピュレーションに対応し、マニピュレーションの動作を何らかの形で変更する特別なコンポーネントです。

![68.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1a723d79-9916-c27c-a461-baa6d084d3bc.png)

## インスペクタのプロパティとフィールド

![59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/19930f12-8bf4-390f-2d05-f4cb3106ad6e.png)

**一般的なプロパティ**

**Host transform**

操作されるオブジェクトのトランスフォームです。デフォルトはコンポーネントのオブジェクトです。

**Manipulation type**

オブジェクトを片手で操作するのか、両手で操作するのかを指定します。このプロパティはフラグなので、両方のオプションを選択することができます。

- 片手:選択された場合、片手での操作を有効にします。
- 両手:選択された場合、両手での操作を有効にします。

**遠距離操作の許可**

ポインタを使った遠近法による操作を許可するかどうかを指定します。

## 片手での操作のプロパティ

**片手回転モード near**

片手で近くを掴んだときのオブジェクトの動作を指定します。これらのオプションはアーティキュレートされた手に対してのみ有効です。

- オブジェクトの中心を中心に回転： オブジェクトは手の回転を利用して回転しますが、オブジェクトの中心点を中心に回転します。オブジェクトは回転に伴って動きが少なくなるように見えますが、手とオブジェクトの間に断絶感が生じることがあります。遠く離れた場所でのインタラクションに有効です。
- つかんだ点を中心に回転：　親指と人差し指の間のグラブポイントを中心に、手でオブジェクトを回転させます。あたかも手で物体を掴んでいるような感覚になります。

**片手回転モード far**

遠くから片手で掴まれているときのオブジェクトの動作を指定します。これらのオプションはアーティキュレートされた手に対してのみ機能します。

- オブジェクトの中心を中心に回転します。手の回転を利用してオブジェクトを回転させますが、オブジェクトの中心点を中心に回転させます。オブジェクトが回転してもオブジェクトの中心が移動しないように、離れた場所から検査するのに便利です。
- つかんだ点を中心に回転：　手の回転を利用して物体を回転させますが、ポインターレイのヒットポイントを中心に回転させます。検査に便利です。

## 両手での操作のプロパティ

**両手操作のタイプ**

両手操作によるオブジェクトの変形方法を指定します。このプロパティはフラグなので、任意の数のオプションを選択できます。

- Move： 選択されている場合、移動が許可されます。
- Scale： 選択されている場合、拡大縮小が可能です。
- Rotate： 選択されている場合、回転が許可されます。


![64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f2114db0-a64c-043e-f652-5e28386b147e.png)

## Constraints

**制約を有効にする**

この設定は、リンクされたconstraint managerを有効にします。Transformの変更は、選択されたconstraint managerに登録された制約によって処理されます。

**Constraint manager**

ドロップダウンでは、接続されている制約マネージャのいずれかを選択できます。オブジェクトマニピュレータは、常にコンストレイントマネージャが接続されていることを保証します。同じタイプの複数のコンポーネントは、ユニティでは同じ名前で表示されることに注意してください。同じオブジェクト上の複数のコンストレイントマネージャーを区別しやすくするために、利用可能なオプションには、選択されたコンストレイントマネージャーの構成に関するヒントが表示されます（手動または自動コンストレイント選択）。

**コンポーネントへ**

制約マネージャの選択には、Go to componentボタンが付いています。このボタンを押すと、インスペクタが選択されたコンポーネントにスクロールして、そのコンポーネントを設定できるようになります。

**Physics 物理**

このセクションの設定は、オブジェクトにRigidBodyコンポーネントがある場合にのみ表示されます。

**リリース動作**

操作されたオブジェクトがリリースされたときに保持すべき物理的特性を指定します。このプロパティはフラグなので、両方のオプションを選択することができます。

速度を保つ。このオプションが選択されていると、オブジェクトがリリースされたときに、その直線速度を維持します。
Keep Angular Velocity（角速度を保つ）。このオプションが選択されていると、オブジェクトがリリースされたときに角速度が維持されます。
近接操作に力を使う
近接操作を行う際、オブジェクトの移動に物理的な力を使用するかどうか。このオプションを false に設定すると、オブジェクトがユーザーの手に直接触れているように感じられます。trueに設定すると、オブジェクトの質量と慣性が尊重されますが、オブジェクトがバネでつながっているように感じられるかもしれません。デフォルトはfalseです。

## スムージング

**Smoothing far**

farのインタラクションに対してフレームレートに依存しないスムージングを有効にするかどうか。デフォルトではfar smoothingが有効になっています。

**Smoothing near**

フレームレートに依存しないスムージングをnearのインタラクションに有効にするかどうか。近距離のスムージングはデフォルトでは無効になっています。これは、エフェクトが手から「切り離されている」と感じられる可能性があるためです。

**Smoothing active**

廃止され、将来のバージョンで削除される予定です。アプリケーションはSmoothingFar、SmoothingNear、またはそれらの組み合わせを使用してください。

**Move lerp time**

動きに適用するスムージングの量です。Smoothing0は、スムージングを行わないことを意味します。最大値は、値に変化がないことを意味します。

**Rotate lerp time**

回転に適用するスムージングの量。スムージングが0の場合は、スムージングなし。最大値は、値に変化がないことを意味します。

**Scale lerp time**

スケールに適用されるスムージングの量。スムージングが0の場合は、スムージングを行わないことを意味します。最大値は値の変更がないことを意味する。

## Manipulation イベント
マニピュレーションハンドラは以下のイベントを提供します。

- OnManipulationStarted: マニピュレーションの開始時に発生します。
- OnManipulationEnded：操作が終了したときに発生します。マニピュレーションの終了時に発生します。
- OnHoverStarted：操作の終了時に発生します。ハンド／コントローラが操作対象物に近づいたり遠ざかったりしたときに発生します。
- OnHoverEnded：操作が終了したときに発生します。ハンド／コントローラがマニピュレータの近くまたは遠くに移動したときに発生します。

マニピュレーションのイベント発生順序は以下の通りです。

OnHoverStarted -> OnManipulationStarted -> OnManipulationEnded -> OnHoverEnded です。

マニピュレーションが行われていない場合は、次のような順序でホバーイベントが発生します。

OnHoverStarted -> OnHoverEnded

## Physics と collisions

物理挙動は、オブジェクトマニピュレーターと同じオブジェクトにリジッドボディコンポーネントを追加することで有効になります。これにより、上記のリリースビヘイビアの設定が可能になるだけでなく、コリジョンも有効になります。リジッドボディコンポーネントがないと、マニピュレーション中のコリジョンは正しく動作しません。

- マニピュレートされたオブジェクトとスタティックコライダ（コライダを持つがリジッドボディを持たないオブジェクト）の衝突は機能せず、マニピュレートされたオブジェクトは影響を受けずにスタティックコライダを通過します。
- 操作されたオブジェクトとリジッドボディ（コライダとリジッドボディの両方を持つオブジェクト）の衝突では、リジッドボディが衝突反応を起こしますが、その反応は飛び飛びで不自然です。また、操作されたオブジェクトにはコリジョン・レスポンスがありません。

リジッドボディが追加されると、コリジョンは正しく動作するはずです。

リジッドボディなし

![30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6f4e2624-81e9-4cf1-d0be-cd739c6a96e8.png)

リジッドボディあり

![205.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6248bfb2-1f22-182d-aaeb-b751e5465680.png)

**Elastics (実験中)**
オブジェクト・マニピュレーターでオブジェクトを操作する際に、エラスティックを使うことができます。ただし、エラスティックのシステムはまだ実験段階です。エラスティックを有効にするには、既存のエラスティックマネージャーコンポーネントをリンクするか、「Add Elastics Manager」ボタンで新しいエラスティックマネージャーを作成してリンクしてください。

![222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d91c8951-bba1-3686-bcc6-b0fe249bf274.png)



# Slate(スレート)

![116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1ec7a748-92d2-ffdb-7022-baca66074289.png)

Slateプレハブは、2Dコンテンツ（プレーンテキストやメディアを含む記事など）を表示する薄型ウィンドウスタイルのコントロールです。掴みやすいタイトルバーや、フォローミーやクローズ機能を備えています。コンテンツウィンドウは、多関節の手入力でスクロールできます。

**スレートコントロールの使い方**

スレートコントロールは、以下の要素で構成されています。

TitleBar: スレートの上部にあるタイトルバー全体。
Title: タイトルバーの左端にあるタイトル領域。
Buttons: タイトルバーの右側にあるボタンエリア。
BackPlate: スレートの裏側です。
ContentQuad: コンテンツはマテリアルとして割り当てられます。この例では、サンプルのマテリアル「PanContent」を使用しています。

![79.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c4af826b-ce8d-4563-9eed-9a9d0127883c.png)

## Bounds control(バウンドコントロール)
スレートコントロールには、拡大縮小や回転のためのバウンズコントロールスクリプトが含まれています。バウンドコントロールの詳細については、バウンドコントロールのページを参照してください。

![173.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0ef1ccc2-2f37-ef32-d827-04e9028e32e3.png)

**ボタン**

標準的なスレートでは、タイトルバーの右上に2つのボタンがデフォルトで用意されています。

- Follow Me: 軌道ソルバーのコンポーネントをトグルして、スレートのオブジェクトがユーザーに追従するようにします。
- Close:  スレートオブジェクトを無効にします。

![73.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/aaa64628-fb7c-f255-7f80-2c9f5ee6203e.png)



**スクリプト**
一般的に、IMixedRealityTouchHandlerからタッチイベントを受け取ることを意図したオブジェクトには、NearInteractionTouchable.csスクリプトをアタッチする必要があります。

![101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/b5b038d2-59b8-bbcd-9fc2-5228ac080d5a.png)

- HandInteractionPan.cs： このスクリプトは、スレートの ContentQuad 上のコンテンツを触ったり動かしたりするための多関節の手の入力を処理します。

- HandInteractionPanZoom.cs：　パンのインタラクションに加えて、このスクリプトは両手でのズームをサポートします。

![74.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fcb81290-eb1f-5e27-4635-9f1f4870cb7c.png)




# System keyboard


![143.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a05fbea5-f876-adcf-f93a-bcce1795f1fb.png)

Unityのアプリケーションは、いつでもシステムキーボードを呼び出すことができます。なお、システムキーボードはターゲットプラットフォームの機能に応じて動作します。例えば、HoloLens 2のキーボードは手による直接のインタラクションをサポートしますが、HoloLens（第1世代）のキーボードはGGV（Gaze, Gesture, and Voice）をサポートします1。また、エディタからHoloLensへのUnity Remotingを行う際には、システムキーボードは表示されません。

**システムキーボードの呼び出し方**

```c#
public TouchScreenKeyboard keyboard;

...

public void OpenSystemKeyboard()
{
    keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.Default, false, false, false, false);
}
```

## 入力の読み方

```c#
public TouchScreenKeyboard keyboard;

...

private void Update()
{
    if (keyboard != null)
    {
        keyboardText = keyboard.text;
        // キーボードテキストを使って何かをする
    }
}
```

**システムキーボードの例**

**MixedRealityKeyboard.cs**(Assets/MRTK/SDK/Experimental/Features/UX/MixedRealityKeyboard.cs)では、システムキーボードを表示する簡単な例を見ることができます。




# Interactable

![52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/088f2cfd-aae9-cca9-2b1d-e457795800ed.png)

Interactableコンポーネントは、あらゆるオブジェクトを簡単にインタラクティブ化し、入力に反応させることができるオールインワンのコンテナです。Interactableは、タッチ、ハンドレイ、スピーチなど、あらゆる種類の入力を受け付ける役割を果たし、これらのインタラクションをイベントやビジュアルテーマのレスポンスに集約します。このコンポーネントは、ボタンの作成、フォーカスされたオブジェクトの色の変更などを簡単に行うことができます。

**Interactableの設定方法**

このコンポーネントでは、主に3つのセクションで設定を行うことができます。

1. 一般的な入力設定
2. 複数のGameObjectに対するビジュアルテーマの設定
3. イベントハンドラー

**一般的な入力設定**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e3aabab9-a751-7cd0-3f13-cdfd39c700af.png)

**状態**

StatesはScriptableObjectのパラメータで、Interactable ProfilesやVisual Themesのpressやobservedなどのインタラクションフェーズを定義します。

**DefaultInteractableStates**（Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset）は、MRTKにそのまま同梱されており、Interactableコンポーネントのデフォルトのパラメータです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7b071dcd-aa8b-4dbd-a175-2bd93f1554e8.png)

DefaultInteractableStatesアセットには4つのステートがあり、InteractableStatesステートモデルの実装を利用しています。

- Default: 何も起きていない、最も孤立した基本状態です。
- Focus: オブジェクトが指されている状態です。これは単一の状態であり、現在は他の状態は設定されていませんが、Defaultよりも上位になる予定です。
- Press: 対象物が指されていて、ボタンや手が押されている状態です。Pressの状態は、DefaultとFocusよりも上位になります。この状態は、Physical Pressのフォールバックとしても設定されます。
- Disabled: ボタンはインタラクティブであってはならず、何らかの理由でこのボタンが現時点で使用できない場合は、視覚的なフィードバックでユーザーに知らせます。理論的には、Disabledの状態に他のすべての状態を含めることができますが、Enabledがオフになっている場合は、Disabledの状態が他のすべての状態に優先します。

リストの順番に応じて、ビット値（#）が状態に割り当てられます。


> 注意
> 
> Interactableコンポーネントを作成する際には、DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset)を使用することをお勧めします。
> 
> しかし、テーマの駆動に使用できるInteractable Statesは17種類ありますが、中には他のコンポーネントで駆動することを前提としているものもあります。ここでは、機能が組み込まれているものを紹介します。
> 
> Visited：Interactableがクリックされた状態です。
> 
> Toggled：ボタンが toggled 状態であるか、Dimension index が奇数である。
> 
> Gesture：手やコントローラが押され、元の位置から移動した。
> 
> VoiceCommand：Interactableの起動に音声コマンドが使用されました。
> 
> PhysicalTouch：タッチ入力が検出されました。NearInteractionTouchableを使用して有効にしてください。
> 
> Grab：オブジェクトの境界内で手が掴まれています。NearInteractionGrabbableを使用して有効にしてください。


**Enabled**

Interactableの有効化を開始するかどうかをトグルします。これはコード上のInteractable.IsEnabledに相当します。

Interactableのenabledプロパティは、GameObject/Componentで設定されたenabledプロパティ（SetActiveなど）とは異なります。GameObjectやInteractableのMonoBehaviourを無効にすると、入力、ビジュアルテーマ、イベントなど、クラス内のすべての動作が無効になります。Interactable.IsEnabledで無効にすると、ほとんどの入力処理が無効になり、関連する入力状態がリセットされます。ただし、クラスはフレームごとに実行され、無視される入力イベントを受け取ります。これは、Interactable を無効な状態で表示するのに便利で、Visual Themes で実現できます。典型的な例は、すべての必須入力フィールドが完了するのを待つ送信ボタンです。

**入力アクション**

入力設定またはコントローラのマッピングプロファイルから、Interactableコンポーネントが反応すべき入力アクションを選択します。

このプロパティは、コードの実行時にInteractable.InputAction.IsGlobalで設定できます。

**IsGlobal**

trueの場合、選択された入力アクションのグローバルな入力リスナーとしてコンポーネントがマークされます。デフォルトの動作はfalseで、このInteractable collider/GameObjectのみに入力を制限します。

このプロパティは、実行時にInteractable.IsGlobalを介してコードで設定できます。

**スピーチコマンド**

MRTK Speech Commands ProfileのSpeechコマンドで、ボイスインタラクションのOnClickイベントをトリガーします。

このプロパティは、実行時に Interactable.VoiceCommand.Speech コマンドを介してコード内で構成することができます。

**Requires Focus**

true の場合、音声コマンドは、Interactable がすでにポインタからフォーカスを受けている場合にのみ、その Interactable をアクティブにします。falseの場合は、Interactableは選択されたボイスコマンドのグローバルリスナーとして動作します。複数のグローバルな音声リスナーをシーン内で整理することは困難なため、デフォルトの動作はtrueです。

このプロパティは、コードの実行時に Interactable.VoiceRequiresFocus で設定できます。

**選択モード**

このプロパティは、選択ロジックを定義します。Interactableがクリックされると、次のDimensionレベルに反復されます。次元はランクに似ており、入力（フォーカス、プレスなど）以外の状態を定義します。ディメンションは、トグルの状態や、ボタンに関連する他のマルチランクの状態を定義するのに便利です。現在のディメンションレベルは、Interactable.DimensionIndexによって追跡されます。

利用可能な選択モードは次のとおりです。

- Button - Dimensions = 1, simple clickable Interactable
- Toggle - 寸法 = 2, オン/オフの状態を交互に繰り返すインタラクタブル
- Multi-dimension - 次元数 >= 3, クリックするたびに現在の次元数 + 1 が増加します。リストにボタンの状態を定義する場合などに便利です。

また、Interactableでは、ディメンションごとに複数のテーマを定義することができます。例えば、SelectionMode=Toggleの場合、Interactableの選択解除時にはあるテーマを適用し、コンポーネントの選択時には別のテーマを適用することができます。

現在の選択モードは、Interactable.ButtonModeを介してランタイムに問い合わせることができます。実行時にモードを更新するには、Interactable.Dimensionsプロパティを希望の機能に合わせて設定することで可能です。さらに、トグルモードやマルチディメンションモードに便利な現在のディメンションは、Interactable.CurrentDimensionでアクセスできます。


## Interactable profiles

プロファイルとは、GameObjectとVisual Themeの関係を作るためのアイテムです。プロファイルは、状態変化が起こったときにテーマによって操作されるコンテンツを定義します。

テーマはマテリアルに似ています。テーマはスクリプト可能なオブジェクトで、現在の状態に基づいてオブジェクトに割り当てられるプロパティのリストを含んでいます。また、テーマは再利用可能で、複数のInteractable UXオブジェクトに割り当てることができます。

**Reset On Destroy(破壊時のリセット)**

ビジュアルテーマは、選択されたテーマエンジンのクラスやタイプに応じて、対象となるGameObjectの様々なプロパティを変更します。Interactableコンポーネントの破壊時にReset On Destroyがtrueの場合、コンポーネントはアクティブなテーマから変更されたすべてのプロパティを元の値にリセットします。そうでない場合は、Interactable コンポーネントが破壊されても、変更されたプロパティはすべてそのまま残ります。後者の場合、他の外部コンポーネントによって変更されない限り、値の最後の状態が維持されます。デフォルトは false です。


![217.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/3a382277-89cc-f167-dc31-20d678316706.png)

**イベント**

すべての Interactable コンポーネントには、単にコンポーネントが選択されたときに発生する OnClick イベントがあります。しかし、Interactableは、OnClick以外の入力イベントを検出するために使用することができます。

[Add Event]ボタンをクリックして、新しいタイプのEvent Receiver定義を追加します。追加したら、必要なイベントの種類を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f8fd9703-bfa6-d7ea-2526-3ae0f2638cfe.png)

さまざまな種類の入力に対応するために、さまざまなタイプのイベントレシーバーがあります。MRTKには、次のようなレシーバーが標準で付属しています。

- InteractableAudioReceiver
- InteractableOnClickReceiver
- InteractableOnFocusReceiver
- InteractableOnGrabReceiver
- InteractableOnHoldReceiver
- InteractableOnPressReceiver
- InteractableOnToggleReceiver
- InteractableOnTouchReceiver

カスタムレシーバーを作成するには、ReceiverBaseを継承した新しいクラスを作成します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7aab5f9d-80b8-4ef0-52fe-b6cb9856ad1c.png)

トグルイベントレシーバの例

## Interactable receivers

InteractableReceiverコンポーネントでは、ソースのInteractableコンポーネントの外部でイベントを定義することができます。InteractableReceiverは、他のInteractableによって発生したフィルタリングされたイベントタイプをリッスンします。Interactableプロパティが直接割り当てられていない場合は、Search Scopeプロパティで、InteractableReceiverがイベントをリッスンする方向を定義します。これは、自分自身、親、または子のGameObjectのいずれかです。

InteractableReceiverListも同様の動作をしますが、マッチするイベントのリストを対象としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/96e5f31f-62fc-44e6-b7e1-95841ebdd2b1.png)

## カスタムイベントの作成

Visual Themes と同様に、イベントは任意の状態パターンを検出したり、機能を公開するように拡張できます。

カスタムイベントは、主に 2 つの方法で作成できます。

ReceiverBaseクラスを拡張して、イベントタイプのドロップダウンリストに表示されるカスタムイベントを作成します。デフォルトではUnityイベントが提供されていますが、Unityイベントを追加したり、Unityイベントを非表示にするように設定することができます。この機能により、デザイナーがプロジェクトのエンジニアと協力してカスタムイベントを作成し、デザイナーがエディターで設定することができます。

ReceiverBaseMonoBehaviorクラスを拡張して、Interactableまたは他のオブジェクトに常駐できる完全にカスタムなイベントコンポーネントを作成。ReceiverBaseMonoBehaviorは、Interactableを参照して状態の変化を検出します。

ReceiverBaseの拡張の例
CustomInteractablesReceiverクラスは、Interactableのステータス情報を表示し、カスタムイベントReceiverの作成例となります。

```c#
public CustomInteractablesReceiver(UnityEvent ev) : base(ev, "CustomEvent")
{
    HideUnityEvents = true; // レシーバー内のUnityイベントを非表示にする - コードのみを意味する
}
```

以下のメソッドは、カスタムイベントレシーバーを作成する際にオーバーライド/実装すると便利です。ReceiverBase.OnUpdate()は、状態パターン／遷移の検出に使用できる抽象メソッドです。さらに、ReceiverBase.OnVoiceCommand()メソッドおよびReceiverBase.OnClick()メソッドは、Interactableが選択されたときのカスタムイベントロジックの作成に役立ちます。

```c#
public override void OnUpdate(InteractableStates state, Interactable source)
{
    if (state.CurrentState() != lastState)
    {
        // 状態が変わったので、何か新しいことをする
        lastState = state.CurrentState();
        ...
    }
}

public virtual void OnVoiceCommand(InteractableStates state, Interactable source,
                                    string command, int index = 0, int length = 1)
{
    base.OnVoiceCommand(state, source, command, index, length);
    // 音声コマンドが呼び出され、何らかのアクションを実行
}  

public virtual void OnClick(InteractableStates state,
                            Interactable source,
                            IMixedRealityPointer pointer = null)
{
    base.OnClick(state, source);
    // 呼び出されたクリックで、何らかのアクションを実行
}
```


**カスタムイベントレシーバーフィールドのインスペクタへの表示**

ReceiverBaseスクリプトはInspectorField属性を使用して、インスペクタでカスタムプロパティを公開します。ここでは、ツールチップとラベル情報を持つカスタムプロパティであるVector3の例を示します。このプロパティは、Interactable GameObjectが選択され、関連するEvent Receiverタイプが追加されると、インスペクタに設定可能なものとして表示されます。

```c#
[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;
```

## Interactableの使い方

**シンプルなボタンの作成**

入力イベントを受け取るように設定されたGameObjectにInteractableコンポーネントを追加することで、シンプルなボタンを作ることができます。入力を受け取るためには、その上や子にコライダを持たせることができます。Unity UIベースのGameObjectにInteractableを使用する場合は、Canvas GameObjectの下に置く必要があります。

ボタンをさらに一歩進めて、新しいプロファイルを作成し、GameObject自体を割り当て、新しいテーマを作成します。さらに、OnClickイベントを使って、何かを起こしてみましょう。


> 注意
> 
> ボタンを押せるようにするには、PressableButtonコンポーネントが必要です。また、プレスイベントをInteractableコンポーネントに流すために、PhysicalPressEventRouterコンポーネントが必要になります。


## トグルボタンとマルチディメンションボタンの作成

**トグルボタン**

ボタンをトグル可能にするには、「選択モード」フィールドを「トグル」と入力します。Profilesセクションでは、Interactableがトグルされたときに使用されるプロファイルごとに、新しいトグルテーマが追加されます。

SelectionModeがToggleに設定されている間は、IsToggledチェックボックスを使用して、ランタイムの初期化時にコントロールのデフォルト値を設定することができます。

CanSelectはInteractableがオフからオンになることを意味し、CanDeselectはその逆を意味します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6d0a114c-a89a-009b-dc61-ce8d19694b5c.png)


開発者は、SetToggled および IsToggled インターフェースを利用して、コードを介して Interactable のトグル状態を取得/設定することができます。

```c#
// SelectionMode = Toggle を使用する場合 (すなわち Dimensions == 2)

// Interactable が選択され、トグルされた状態になります。
myInteractable.IsToggled = true;

// インタラクティブルが選択されているかどうかを取得する
bool isSelected = myInteractable.IsToggled;
```

**トグルボタンコレクション**

放射状セットやラジオボタンなどで知られているように、いつでも1つだけがアクティブになるトグルボタンのリストを持つことは一般的です。

この機能を有効にするには、InteractableToggleCollectionコンポーネントを使用します。このコントロールは、いつでも1つのInteractableだけがトグルされるようにします。RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab)は、すぐに使用できる優れた出発点となります。

カスタム放射状ボタングループを作るには

1. 複数のInteractable GameObjects/buttonsを作成する。
2. 各InteractableにSelectionMode = Toggle、CanSelect = true、CanDeselect = falseを設定する。
3. すべてのInteractableの上に空の親GameObjectを作成し、InteractableToggleCollectionコンポーネントを追加する。
4. すべてのInteractableをInteractableToggleCollectionのToggleListに追加する
5. InteractableToggleCollection.CurrentIndexプロパティを設定し、開始時にどのボタンがデフォルトで選択されているかを決める

![80.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/087718e4-905c-31ee-b185-5051ccc40dba.png)

**多次元ボタン**

多次元選択モードは、連続したボタンや、2つ以上のステップを持つボタンを作成するために使用されます。例えば、Fast（1x）、Faster（2x）、Fastest（3x）の3つの値で速度を制御するような場合です。

ディメンションが数値であることから、最大9個のテーマを追加して、各速度設定のボタンのテキストラベルやテクスチャを制御することができ、各ステップごとに異なるテーマを使用することができます。

各クリックイベントは、ランタイムにDimensionIndexを1ずつ進め、Dimensionsの値に到達します。その後、このサイクルは0にリセットされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/471795e8-ccb7-475a-82f9-ecc90ea604bd.png)

開発者はDimensionIndexを評価して、どのディメンションが現在アクティブかを判断することができます。

```c#
// SelectionMode = Multi-dimension (すなわちDimensions >= 3)を使用する場合

//現在のDimensionIndexにアクセスします。
int currentDimension = myInteractable.CurrentDimension;

//現在のDimensionIndexを2に設定
myInteractable.CurrentDimension = 2;

//ディメンションを次のレベルに昇格させる
myInteractable.IncreaseDimension();
```

**実行時にインタラクタブルを作成する**

Interactableは、ランタイムに任意のGameObjectに簡単に追加することができます。以下の例では、ビジュアルテーマを持つプロファイルを割り当てる方法を示しています。

```c#
var interactableObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
var interactable = interactableObject.AddComponent<Interactable>();

// テーマエンジンのデフォルト設定を取得 InteractableColorTheme
var newThemeType = ThemeDefinition.GetDefaultThemeDefinition<InteractableColorTheme>().Value;

// Default Interactable Statesの各ステートに色を定義する
newThemeType.StateProperties[0].Values = new List<ThemePropertyValue>()
{
    new ThemePropertyValue() { Color = Color.black},  // Default
    new ThemePropertyValue() { Color = Color.black}, // Focus
    new ThemePropertyValue() { Color = Random.ColorHSV()},   // Pressed
    new ThemePropertyValue() { Color = Color.black},   // Disabled
};

interactable.Profiles = new List<InteractableProfileItem>()
{
    new InteractableProfileItem()
    {
        Themes = new List<Theme>()
        {
            Interactable.GetDefaultThemeAsset(new List<ThemeDefinition>() { newThemeType })
        },
        Target = interactableObject,
    },
};

// Force the Interactable to be clicked
interactable.TriggerOnClick()
```


**コードによるインタラクタブルイベント**

以下の例のように、ベースとなるInteractable.OnClickイベントにコードでアクションを追加することができます。

```c#
public static void AddOnClick(Interactable interactable)
{
    interactable.OnClick.AddListener(() => Debug.Log("Interactable clicked"));
}
```

実行時にイベントレシーバーを動的に追加するには、Interactable.AddReceiver<T>()関数を使用します。

以下のサンプルコードでは、フォーカスの入退出をリスンする InteractableOnFocusReceiver を追加し、さらにイベントインスタンスの発火時に実行するアクションコードを定義する方法を示しています。

```c#
public static void AddFocusEvents(Interactable interactable)
{
    var onFocusReceiver = interactable.AddReceiver<InteractableOnFocusReceiver>();

    onFocusReceiver.OnFocusOn.AddListener(() => Debug.Log("Focus on"));
    onFocusReceiver.OnFocusOff.AddListener(() => Debug.Log("Focus off"));
}
```

以下のサンプルコードでは、InteractableOnToggleReceiverを追加する方法を示しています。このReceiverは、トグル可能なInteractableの選択/非選択状態の遷移をリッスンし、さらにイベントインスタンスが発火したときに実行するアクションコードを定義します。

```c#
public static void AddToggleEvents(Interactable interactable)
{
    var toggleReceiver = interactable.AddReceiver<InteractableOnToggleReceiver>();

    // インタラクテブルにトグル機能を持たせます。
    // GUI エディタではもっと簡単です。
    interactable.Dimensions = 2;
    interactable.CanSelect = true;
    interactable.CanDeselect  = true;

    toggleReceiver.OnSelect.AddListener(() => Debug.Log("Toggle selected"));
    toggleReceiver.OnDeselect.AddListener(() => Debug.Log("Toggle un-selected"));
}
```


# Solvers

![256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/910c9fb2-4562-3762-5dda-ced26284beac.png)

ソルバーとは、あらかじめ定義されたアルゴリズムに従って、オブジェクトの位置と向きを計算する手段を容易にするコンポーネントです。例えば、ユーザーの視線のレイキャストが現在当たっている面にオブジェクトを配置することができます。

さらに、コンポーネントの更新順序をUnityに指定する信頼性の高い方法がないため、ソルバーシステムは、これらのトランスフォーム計算の操作順序を決定論的に定義します。

ソルバーには、オブジェクトを他のオブジェクトやシステムにアタッチするための様々なビヘイビアが用意されています。他の例としては、（カメラに基づいて）ユーザーの前でホバリングするタグアロングオブジェクトがあります。また、ソルバーをコントローラとオブジェクトに取り付けて、オブジェクトをコントローラにタグアロングさせることもできる。すべてのソルバーは、安全に積み重ねることができます。例えば、タグアロング・ビヘイビア＋表面磁力＋運動量のように。

## ソルバーの使い方

ソルバーシステムは、3つのカテゴリーのスクリプトで構成されています。

- ソルバー: すべてのソルバーが派生するベースとなる抽象クラスです。状態の追跡、スムージングのパラメータと実装、ソルバーシステムの自動統合、更新順序などを提供します。
- SolverHandler: 追従する参照オブジェクト（例：メインカメラのトランスフォーム、ハンドレイなど）を設定し、ソルバーコンポーネントの収集を処理し、適切な順序で更新を実行します。
3つ目のカテゴリーは、ソルバーそのものです。以下のソルバーは、基本的な動作の構成要素を提供します。

- Orbital(軌道)：参照されるオブジェクトからの指定された位置とオフセットにロックします。
- ConstantViewSize：参照されるオブジェクトのビューに対して一定のサイズを保つようにスケーリングします。
- RadialView（ラジアルビュー）：RadialView: 参照されるオブジェクトのビューコーン内にオブジェクトを保持します。
- Follow：参照されるオブジェクトのユーザー定義の境界線内にオブジェクトを保持する。
- InBetween：2つのトラッキングオブジェクトの間にオブジェクトを保持します。
- SurfaceMagnetism：ワールド内のサーフェスに光線を当て、オブジェクトをそのサーフェスに合わせます。
- DirectionalIndicator（方向指示器）：方向指示器としてのオブジェクトの位置と向きを決定します。- - SolverHandler Tracked Targetの参照点から、このインジケータは指定されたDirectionalTargetに向かって進みます。
- Momentum：他のソルバーやコンポーネントによって動かされているオブジェクトの運動量とバネ性をシミュレートするために、加速度/速度/摩擦を適用します。
- HandConstraint（手の拘束）：GameObjectと手が交差しない領域で手を追うようにオブジェクトを制限する。メニューなどのインタラクティブなコンテンツで、手の動きを制限する場合に有効。このソルバーは、IMixedRealityHandでの動作を想定していますが、IMixedRealityControllerでも動作します。
- HandConstraintPalmUp：HandConstraintから派生したものですが、起動前に手のひらがユーザーに向いているかどうかをテストするロジックが含まれています。このソルバーは、IMixedRealityHandコントローラでのみ動作し、他のコントローラタイプでは、このソルバーはベースクラスと同様に動作します。

ソルバーシステムを使用するには、上記のコンポーネントの1つをゲームオブジェクトに追加するだけです。すべてのソルバーはSolverHandlerを必要とするので、Unityによって自動的に作成されます。


> 注意
> 
> Solverシステムの使い方の例は、SolverExamples.sceneファイルに記載されています。


## トラッキングリファレンスの変更方法
SolverHandlerコンポーネントのTracked Target Typeプロパティは、すべてのソルバーがアルゴリズムを計算する際に使用する参照点を定義します。例えば、単純なSurfaceMagnetismコンポーネントで値のタイプがHeadの場合、どのサーフェイスがヒットしたかを解決するために、頭からのレイキャストとユーザーの視線の方向になります。TrackedTargetTypeプロパティに指定できる値は以下の通りです。

- Head：参照点はメインカメラのトランスフォーム
- ControllerRay：基準点は、ラインレイの方向を指しているコントローラのLinePointer変換（モーションコントローラやハンドコントローラのポインタの原点など）。
  - TrackedHandednessプロパティを使用して、ハンドネスの優先順位を選択する（例：左、右、両方）。
- HandJoint：リファレンスのポイントは、特定のハンドジョイントのトランスフォームです。
  - TrackedHandedness プロパティを使用して、ハンドネスの優先順位を選択します（例：左、右、両方）。
  - TrackedHandJointプロパティを使用して、利用するジョイントトランスフォームを決定します。
- CustomOverride：割り当てられた TransformOverride からの参照点



> 注意
> 
> ControllerRayとHandJointの両タイプとも、ソルバーハンドラーは、左のコントローラ/ハンドのトランスフォームが利用できない場合やTrackedHandednessプロパティで指定されていない場合は、まず左のコントローラ/ハンドのトランスフォームを提供しようとし、次に右のトランスフォームを提供します。


![84.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c147b016-cf6d-995b-a7ab-a783a0ec594d.png)

> 重要
> 
> ほとんどのソルバーは、SolverHandlerによって提供された追跡されたトランスフォームターゲットの前方ベクトルを使用します。ハンドジョイントのトラッキングターゲットタイプを使用する場合、パームジョイントのフォワードベクターは指を通り、パームを通らない場合があります。これは、ハンドジョイントのデータを提供するプラットフォームによって異なります。入力シミュレーションやWindows Mixed Realityでは、手のひらを上に向けたアップベクトルとなります（例：緑のベクトルが上、青のベクトルが前）。
> 
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/bf42b6cd-cecc-2fde-88a6-735e91abd348.png)
> 
> この問題を解決するには、SolverHandlerのAdditional Rotationプロパティを<90, 0, 0>に更新します。これにより、ソルバーに供給される前方ベクトルが、手のひらを通り、手から離れた外側を指すようになります。
> 
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0eaad4fe-5f21-2f75-3418-28f30e27ad7e.png)
> 
> 別の方法としては、Controller Rayのトラッキングされたターゲットタイプを使用して、手で指し示す際に同様の動作をさせることができます。



**ソルバーを連鎖させる方法**

同じGameObjectに複数のSolverコンポーネントを追加して、アルゴリズムを連鎖させることができます。SolverHandlerコンポーネントは、同じGameObject上のすべてのソルバーのアップデートを処理します。デフォルトでは、SolverHandlerはStart時にGetComponents<Solver>()を呼び出し、インスペクタに表示される順にソルバーを返します。

さらに、Updated Linked Transformプロパティをtrueに設定すると、ソルバーが計算した位置、向き、スケールを、すべてのソルバーがアクセス可能な中間変数（GoalPositionなど）に保存するよう指示します。falseの場合、ソルバーはGameObjectのトランスフォームを直接更新します。トランスフォームのプロパティを中間的な場所に保存することで、他のソルバーは中間的な変数を起点に計算を行うことができる。これは、UnityではgameObject.transformの更新を同一フレーム内で重ねることができないためです。


> 注意
> 
> 開発者は、SolverHandler.Solversプロパティを直接設定することで、ソルバーの実行順序を変更することができます。


**新しいソルバーの作成方法**

すべてのソルバーは、抽象ベースクラスであるSolverを継承する必要があります。ソルバーの拡張に必要なのは、SolverUpdateメソッドのオーバーライドです。このメソッドでは、開発者は継承したGoalPosition、GoalRotation、GoalScaleの各プロパティを希望の値に更新する必要があります。さらに、一般的には、SolverHandler.TransformTargetをコンシューマが求める参照フレームとして活用することが重要です。

以下のコードは、InFrontという新しいSolverコンポーネントの例で、アタッチされたオブジェクトをSolverHandler.TransformTargetの2m前に配置しています。コンシューマでSolverHandler.TrackedTargetTypeがHeadに設定されている場合、SolverHandler.TransformTargetはカメラのトランスフォームとなり、このSolverはアタッチされたGameObject 2mを毎フレームユーザーの視線の先に配置します。

```c#
/// <summary>
/// InFrontソルバーは、トラッキングされたトランスフォームターゲットの2m前にオブジェクトを配置する
/// </summary>
public class InFront : Solver
{
    ...

    public override void SolverUpdate()
    {
        if (SolverHandler != null && SolverHandler.TransformTarget != null)
        {
            var target = SolverHandler.TransformTarget;
            GoalPosition = target.position + target.forward * 2.0f;
        }
    }
}
```

## ソルバーの実装ガイド

**ソルバーの共通プロパティ**

すべてのソルバーコンポーネントには、ソルバーの中核となる動作を制御する同一のプロパティが用意されています。

Smoothingが有効な場合、ソルバーはGameObjectのtransformを計算された値に時間をかけて徐々に更新します。この変化のスピードは、各トランスフォームコンポーネントのLerpTimeプロパティによって決まります。例えば、MoveLerpTimeの値を大きくすると、フレーム間の動きの増分が遅くなります。

MaintainScaleを有効にすると、ソルバーはGameObjectのデフォルトのローカルスケールを利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c53e98d3-6654-5707-d10a-9842dcbf1d55.png)


すべてのソルバーコンポーネントに継承される共通のプロパティ

**オービタル**

Orbitalクラスは、太陽系の惑星のように振る舞うタグ・アロング・コンポーネントです。このソルバーは、アタッチされたGameObjectがトラッキングされたトランスフォームの周りを周回するようにします。つまり、SolverHandlerのTracked Target TypeがHeadに設定されている場合、GameObjectは固定オフセットを適用してユーザーの頭の周りを周回します。

開発者はこの固定オフセットを変更して、メニューやその他のシーンコンポーネントを目の高さや腰の高さなど、ユーザーの周りに保つことができます。これは、ローカルオフセットとワールドオフセットのプロパティを変更することで可能です。Orientation Typeプロパティは、オブジェクトに適用される回転を決定します。オリジナルの回転を維持するのか、常にカメラを向くのか、位置を動かすトランスフォームを向くのか、などです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/929948bf-a2a8-0c40-ecbe-e5c72586ecbb.png)

軌道の例

**ラジアルビュー**

RadialViewは、GameObjectの特定の部分を、ユーザーの視界の範囲内に収めるための、もう一つのタグ付きコンポーネントです。

Min & Max View Degreesプロパティは、GameObjectの一部が常に視界に入っていなければならない大きさを決定します。

Min & Max Distanceプロパティは、GameObjectがユーザーからどのくらい離れているかを設定します。例えば、Min Distanceを1mに設定してGameObjectに向かって歩くと、GameObjectが押し流されて、1m以上近づかないようにすることができます。

通常、RadialViewはTracked Target TypeをHeadに設定して使用し、コンポーネントがユーザーの視線を追うようにします。しかし、このコンポーネントはどのようなTracked Target Typeでも「視界」に入るように機能させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/41e9ef6b-ab65-1a98-17ec-1fbdbab55491.png)

RadialViewの例

**フォロー**

Followクラスは、トラッキングされたターゲットの前に、そのローカルな前方軸に対して要素を配置します。エレメントは、ターゲットがユーザーの定義した範囲を超えて移動するまで追従しないように、ゆるい制約（別名：タグアロング）を受けることができます。

これはRadialViewソルバーと同様に動作しますが、水平・垂直方向の最大表示角度を管理するコントロールや、オブジェクトのオリエンテーションを変更するメカニズムが追加されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f11f3b08-b5d6-81ad-b0f6-cd73898069c1.png)

フォローのプロパティ

![254.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/dddcdf53-30e6-a889-d842-0213d86a9b23.png)

Follow Example Scene (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)

**InBetween**

InBetweenクラスは、アタッチされたGameObjectを2つのトランスフォームの間に保持します。この2つのトランスフォームのエンドポイントは、GameObject自身のSolverHandler Tracked Target TypeとInBetweenコンポーネントのSecond Tracked Target Typeプロパティで定義されます。一般的には、両方のタイプをCustomOverrideに設定し、SolverHandler.TransformOverrideとInBetween.SecondTransformOverrideの値を2つのトラッキングされたエンドポイントに設定します。

InBetweenコンポーネントは、ランタイムに、Second Tracked Target TypeとSecond Transform Overrideプロパティに基づいて、別のSolverHandlerコンポーネントを作成します。

PartwayOffsetは、2つのトランスフォーム間の線上のどこにオブジェクトを配置するかを定義するもので、0.5を中間点、1つ目のトランスフォームで1.0、2つ目のトランスフォームで0.0とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e4f7e82e-203e-b525-7703-c61902170f1a.png)

InBetweenソルバーを使用して、2つのトランスフォームの間にオブジェクトを保持する例です。

**表面磁力**

SurfaceMagnetismは、設定されたLayerMaskのサーフェスに対してレイキャストを行い、その接触点にGameObjectを配置します。

Surface Normal Offsetは、サーフェイス上のヒットポイントの法線方向に、サーフェイスから設定された距離（メートル）だけGameObjectを配置します。

逆に Surface Ray Offset は、GameObject を表面から一定の距離（m）離れた場所に配置しますが、レイキャストが行われた方向とは逆になります。つまり、レイキャストがユーザーの視線であれば、GameObjectはサーフェス上のヒットポイントからカメラまでのラインに沿って近づくことになります。

Orientation Modeは、サーフェス上の法線に関連して適用する回転のタイプを決定します。

- None - 回転は適用されません。
- TrackedTarget - オブジェクトは、レイキャストを駆動する追跡されたトランスフォームに直面します。
- SurfaceNormal - サーフェスのヒットポイントの法線に基づいてオブジェクトが配置されます。
- Blended - オブジェクトは、サーフェス上のヒットポイントの法線と、追跡されたトランスフォームの向きに基づいて整列します。

None以外のモードで、関連するGameObjectを強制的に垂直に保つには、Keep Orientation Verticalを有効にしてください。


> 注意
> 
> Orientation Blendプロパティを使って、Orientation ModeがBlendedに設定されている時の回転要素のバランスをコントロールします。値が0.0の場合は、TrackedTargetモードで完全にオリエンテーションが駆動され、値が1.0の場合は、SurfaceNormalで完全にオリエンテーションが駆動されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2d50f8bd-170d-e26a-44a4-b7860a3b0af5.png)


**ヒットさせることができるサーフェスを決定する**

SurfaceMagnetismコンポーネントをGameObjectに追加する際には、GameObjectのレイヤーとその子（コリダーがある場合）を考慮することが重要です。このコンポーネントは、様々な種類のレイキャストを実行して、どのサーフェイスに「磁力」を当てるかを判断します。ソルバーのGameObjectがSurfaceMagnetismのMagneticSurfacesプロパティに記載されているレイヤーにコライダを持っている場合、レイキャストが自分自身に当たってしまい、GameObjectが自分のコライダポイントにくっついてしまうことがあります。この奇妙な挙動は、メインのGameObjectと全ての子オブジェクトをIgnore Raycastレイヤーに設定するか、MagneticSurfaces LayerMask配列を適切に変更することで回避できます。

逆に、SurfaceMagnetismのゲームオブジェクトは、MagneticSurfacesプロパティに記載されていないレイヤーのサーフェスとは衝突しません。一般的には、すべての必要なサーフェスを専用のレイヤー（Surfacesなど）に配置し、MagneticSurfacesプロパティをこのレイヤーだけに設定することをお勧めします。デフォルトまたはすべてを使用すると、UIコンポーネントやカーソルがソルバーに寄与することがあります。

最後に、MaxRaycastDistanceプロパティの設定よりも遠いサーフェスは、SurfaceMagnetismのレイキャストによって無視されます。

**方向指示子（DirectionalIndicator**

DirectionalIndicatorクラスは、空間内の任意の点の方向に自分自身を向けるタグアロングコンポーネントです。

SolverHandlerのTracked Target TypeがHeadに設定されている場合によく使われます。このようにして、DirectionalIndicatorソルバーを持つUXコンポーネントは、ユーザーに空間の希望するポイントを見るように指示します。

空間内の希望のポイントは、Directional Targetプロパティによって決定されます。

Directional Targetがユーザーに見える場合、またはSolverHandlerで設定された参照フレームが何であれ、このソルバーはその下にあるすべてのRendererコンポーネントを無効にします。見ることができない場合は、すべてがインジケータ上で有効になります。

インジケータのサイズは、ユーザーがDirectional TargetをFOV内に捉えようとするほど小さくなります。

- Min Indicator Scale - インジケータオブジェクトの最小スケールです。
- Max Indicator Scale - インジケータオブジェクトの最大スケールです。
- Visibility Scale Factor - Directional Targetのポイントが見えるか見えないかを判断するFOVを増減させる乗数。
- View Offset - 参照フレームの視点（カメラの可能性）から、このプロパティは、ビューポートの中心からオブジェクトがインジケータ方向にどのくらい離れているべきかを定義します。


![135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/61e7f664-dcc0-7a2e-7a43-0b42cd7f206c.png)

方向指示器のプロパティ

![223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7efd9cfa-a254-1165-23fc-ad526bf1d178.png)

Directional Indicator Example Scene (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

**HandConstraintとHandConstraintPalmUpを使ったハンドメニュー**

![69.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/92247606-d1d2-0b5a-6de8-ac065822e7aa.png)

HandConstraintビヘイビアは、トラッキングされたオブジェクトを、手で制約されたコンテンツ（ハンドUI、メニューなど）にとって安全な領域に制約するソルバーを提供します。安全な領域とは、手と交差しない領域と考えられます。HandConstraintPalmUpというHandConstraintの派生クラスも含まれており、手のひらがユーザーに向いているときにソルバーの追跡オブジェクトをアクティブにするという一般的な動作を示しています。

Hand Constraintソルバーを使ったハンドメニューの作成例は、ハンドメニューのページをご覧ください。


# Object collection

![109.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/3b1e41f5-7c05-2096-cdae-36aa3e939022.png)


オブジェクトコレクションは、オブジェクトの配列を定義済みの3次元形状にレイアウトするためのスクリプトです。平面、円柱、球体、放射状など、さまざまなサーフェススタイルをサポートしています。Unityのあらゆるオブジェクトに対応しているので、2Dと3Dの両方のオブジェクトのレイアウトに使用できます。

## Object collection scripts

- GridObjectCollectionは、円柱、平面、球、放射状のサーフェスタイプに対応しています。
- ScatterObjectCollectionは、散布スタイルのコレクションに対応しています。
- TileGridObjectCollectionは、GridObjectCollectionにいくつかの追加オプションを提供します。注意：TileGridObjectCollectionはGridObjectCollectionを拡張したものではなく、いくつかのバグがあります（issue 6237参照）。そのため、GridObjectCollectionの使用を推奨します。


![121.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/354d59b1-3aca-8565-3218-bd0a5024af6f.png)
Grid Object Collection - Cylinder

![130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/79ecbbc2-3bdd-222d-f965-ee4b21b3b55e.png)
Grid Object Collection - Sphere

![263.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5868fe4f-6042-7d96-8994-9240c02ac287.png)
Grid Object Collection - Radial

![211.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c47a82c1-5b99-8401-a925-93ede7220074.png)
Grid Object Collection - Plane

![148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/700f6980-6132-4e9e-2ffd-15b1b09e588b.png)
Scattered Object Collection

![122.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7245be1e-084c-ea69-1c05-f61a68303afd.png)
Tile Grid Object Collection

## オブジェクトコレクションの使用方法

コレクションを作るには、空のGameObjectを作り、そこにObject Collectionスクリプトを1つ割り当てます。このGameObjectの子オブジェクトとして、任意のオブジェクトを追加することができます。子オブジェクトの追加が終わったら、インスペクタパネルのUpdate Collectionボタンをクリックして、オブジェクトコレクションを生成します。オブジェクトはコレクションのパラメータに応じてシーンに配置されます。Update Collectionには、コードからもアクセスできます。

![232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9ffa22fe-06cb-6547-b57e-89eab9767707.png)


**GridObjectCollectionのコンテンツの配置**

GridObjectCollection のコンテンツは、親オブジェクトがコレクションの上/中/下、左/中央/右に固定されるように整列させることができます。コンテンツの配置を指定するには、anchor プロパティを使用します。

**GridObjectCollection レイアウト順序**

Layout フィールドを使用して、子供たちがレイアウトされる行/列の順序を指定します。

- Column Then Row（列の後に行） - 水平方向（列単位）に並べられた後、垂直方向（行単位）に並べられます。Num Columns（またはコードのColumnsプロパティ）を使用して、グリッドの列数を指定します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5f4574b7-51b3-e1ab-0c45-f99ede6a2d9c.png)


- Row Then Column（行の後に列） - 子供たちはまず垂直方向（行ごと）にレイアウトされ、次に水平方向（列ごと）にレイアウトされます。グリッド内の行数を指定するには Num Rows（またはコード内の Rows プロパティ）を使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e9faa1a7-92de-1962-b4ef-94d03628530a.png)


- Horizontal(水平) - 子供たちは、列のみを使用して1つの行にレイアウトされます。

- Vertical(垂直) - 行のみを使用して、子供たちは1つの列にレイアウトされます。

## オブジェクトコレクションの例
ObjectCollectionExamples (Assets/MRTK/Examples/Demos/UX/Collections/Scenes/ObjectCollectionExamples.unity)のサンプルシーンには、オブジェクトコレクションタイプの様々な例が含まれています。

元素の周期表」は、オブジェクトコレクションがどのように機能するかを示すサンプルアプリです。このアプリでは、オブジェクトコレクションを使用して、3D要素ボックスをさまざまな形状にレイアウトしています。

**オブジェクトコレクションの種類**

**3Dオブジェクト**

オブジェクトコレクションは、インポートされた3Dオブジェクトのレイアウトに使用できます。下の例では、3Dの椅子のモデルオブジェクトをコレクションを使って平面と円筒形にレイアウトしています。

![241.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1a4328d0-6871-5c1e-7f5e-b618d11ba973.png)

**2Dオブジェクト**

オブジェクトコレクションは、2D画像からも作成することができます。例えば、複数の画像を格子状に配置することができます。

![110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6c08da77-856c-890e-748b-2e504f7b053e.png)

# Tooltip

![144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fbf40601-5e36-e3ca-979e-b27c4caaade1.png)

ツールチップは、通常、オブジェクトをよく見たときにヒントや追加情報を伝えるために使用されます。ツールチップは、物理的環境にあるオブジェクトの注釈にも使用できます。

## ツールチップの使用方法

ツールチップはヒエラルキーに直接追加して、オブジェクトをターゲットにすることができます。

この方法を使うには、ゲームオブジェクトとツールチッププレハブの1つ（Assets/MRTK/SDK/Features/UX/Prefabs/Tooltips）をシーン階層に追加します。プレハブのインスペクタパネルで、ToolTipスクリプトを展開します。チップの状態を選択して、ツールチップを設定します。テキストフィールドにツールチップ用のテキストを入力します。ToolTipConnectorスクリプトを展開し、ツールチップを付けるオブジェクトを階層から「ターゲット」と書かれたフィールドにドラッグします。これにより、ツールチップがオブジェクトに取り付けられます。

![240.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f351e180-69f1-56de-3095-61e1c20ae9a1.png)



この用途では、常に表示されているツールチップや、ツールチップコンポーネントのtooltip stateプロパティを変更することでスクリプトを介して表示/非表示を切り替えるツールチップを想定しています。

## ツールチップの動的な生成

ツールチップは、実行時にオブジェクトに動的に追加することができ、タップやフォーカスで表示/非表示を事前に設定することもできます。ToolTipSpawnerスクリプトを任意のゲームオブジェクトに追加するだけです。スクリプトインスペクタでは、表示と非表示の遅延時間を設定できます。また、ライフタイムを設定して、設定した時間が経過するとツールチップが消えるようにすることもできます。ツールチップには、スポーナースクリプトの背景ビジュアルなどのスタイルプロパティもあります。デフォルトでは、ツールチップはスポーンナースクリプトでオブジェクトに固定されます。これを変更するには、AnchorフィールドにGameObjectを指定します。

**サンプルシーン**

サンプルシーン(Assets/MRTK/Examples/Demos/UX/Tooltips/Scenes)では、様々なツールチップの例を見ることができます。


![176.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7a996c4b-66dd-58ed-261b-42f9cc705d9e.png)

# Sliders

![186.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/28c1ffee-7271-4ef8-3354-057f588edf3a.png)

スライダーは、トラック上のスライダーを動かすことで、値を連続的に変化させることができるUIコンポーネントです。現在、ピンチスライダーは、スライダーを直接掴んでも、離れた場所から掴んでも動かすことができます。スライダーは、モーションコントローラ、手、またはGesture + Voiceを使って、ARやVRで動作します。

**シーン例**

MRTK/Examples/Demos/UX/Slider/Scenes/の下にあるSliderExampleシーンで例を見ることができます。

## スライダーの使い方
PinchSlider」プレハブをシーン階層にドラッグ＆ドロップします。独自のスライダーを作成したい場合は、以下の点に注意してください。

- thumbオブジェクトにコライダが付いていることを確認します。PinchSliderプレハブでは、SliderThumb/Button_AnimationContainer/Slider_Buttonにコライダがあります。
- スライダーを近くでつかめるようにしたい場合は、コライダを含むオブジェクトにNear Interaction Grabbableコンポーネントがあることを確認してください。

また、以下のような階層構造を使用することをお勧めします。

- PinchSlider - sliderComponentが含まれています。
- SliderThumb - 移動可能なサムが含まれています。
- TrackVisuals - トラックとその他のビジュアルを含みます。
- OtherVisuals - その他のビジュアルが含まれます。

**スライダーイベント**

スライダーは、以下のイベントを公開しています。

- OnValueUpdated - スライダーの値が変更されるたびに呼び出されます。
- OnInteractionStarted - ユーザーがスライダーを掴んだときに呼び出されます。
- OnInteractionEnded - ユーザーがスライダーを離したときに呼び出されます。
- OnHoverEntered - ユーザーの手やコントローラーがスライダーの上に乗ったときに呼び出されます（近距離または遠距離のインタラクションを使用します）。
- OnHoverExited - ユーザーの手やコントローラーがスライダーの近くにいなくなったときに呼び出されます。

**スライダーのバウンドと軸の設定**

Scene内のハンドルを動かすことで、スライダの始点と終点を直接動かすことができます。

![184.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1a280220-94e6-cea7-7162-48f0dcc2c88a.png)

また、Slider Axisフィールドでスライダーの軸（ローカル空間での）を指定することもできます。

ハンドルを使用できない場合は、代わりに Slider Start Distance と Slider End Distance フィールドでスライダーの始点と終点を指定することができます。スライダーの開始／終了位置は、スライダーの中心からの距離として、ローカル座標で指定します。つまり、スライダーの開始と終了の距離を思い通りに設定した後は、開始と終了の距離を更新することなく、スライダーを小さくしたり大きくしたりすることができます。

**インスペクタのプロパティ**

- Thumb Root スライダーのサムを含むゲームオブジェクトです。
- Slider Value スライダの値です。
- Track Visuals スライダーに沿ったトラックビジュアルを含むゲームオブジェクト。
- Tick Marks スライダーに沿って表示される目盛りを含むゲームオブジェクトです。
- Thumb Visuals スライダに沿って進む希望のサムビジュアルを含むゲームオブジェクトです。
- Slider Axis スライダが移動する軸です。
- Slider Start Distance(スライダ開始距離) スライダ軸の中心からの距離をローカル空間単位で表した もので、スライダトラックの開始位置です。
- Slider End Distance(スライダ終了距離) スライダ軸の中心からの距離で、ローカルスペース単位で表したスライダトラックの終了点。

ユーザがエディタでスライダ軸の値を更新すると、Track Visuals または Tick Visuals が指定されている場合、それらのトランスフォームが更新されます。具体的には、ローカルの位置がリセットされ、ローカルの回転がスライダ軸の方向と一致するように設定されます。それらのスケールは変更されません。Tick Marks に Grid Object Collection コンポーネントがある場合、Layout と CellWidth または CellHeight が Slider Axis に合わせて更新されます。


# MRTK Standard Shader(MRTK標準シェーダ)

![46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/de6bf507-1a76-9b9c-8b90-bc2d46a5a4df.png)

MRTK Standardシェーディングシステムは、UnityのStandard Shaderと同様のビジュアルを実現し、Fluent Design Systemの原則を実装し、Mixed Realityデバイスでもパフォーマンスを維持できる、柔軟性の高い単一のシェーダーを利用しています。

**シーン例**

シェーダーマテリアルの例は、MRTK/Examples/Demos/StandardShader/Scenes/にあるMaterialGalleryシーンで見ることができます。このシーンのマテリアルはすべてMRTK/Standardシェーダを使用しています。

![219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a7de90b7-b66f-9815-820b-773916a10610.png)

MRTK/Examples/Demos/StandardShader/Scenes/の下にあるStandardMaterialComparisonシーンでは、Unity/Standardシェーダの例に対してMRTK/Standardシェーダを比較してテストするための比較シーンを見つけることができます。

![72.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/57907155-b22c-2d0e-87f7-d79cd09e7f82.png)

**アーキテクチャ**

MRTK/Standardシェーディングシステムは、Unityのシェーダープログラムバリアント機能を利用して、マテリアルのプロパティに基づいて最適なシェーダーコードを自動生成する「ユーバーシェーダー」です。ユーザーがマテリアルインスペクタでマテリアルのプロパティを選択すると、有効にした機能についてのみパフォーマンスコストが発生します。

**マテリアルインスペクタ**

MRTK/Standardシェーダには、MixedRealityStandardShaderGUI.csというカスタムマテリアルインスペクタがあります。このインスペクタは、ユーザの選択に基づいてシェーダの機能を自動的に有効／無効にし、レンダリング状態の設定を支援します。各機能の詳細については、Unityエディタで各プロパティにカーソルを合わせるとツールチップが表示されます。

![194.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f36f5cd8-65d5-64b1-982e-57b401d96c8c.png)

インスペクタの最初の部分は、マテリアルのレンダリング状態を制御します。レンダリングモードは、マテリアルがいつ、どのようにレンダリングされるかを決定します。MRTK/Standardシェーダの目的は、Unity/Standardシェーダにあるレンダリングモードをミラーリングすることです。MRTK/Standardシェーダには、AdditiveレンダリングモードとCustomレンダリングモードが含まれており、ユーザーが完全にコントロールできるようになっています。


|レンダリングモード| 説明|
|:--|:--|
|Opaque|（デフォルト）透過部分のない通常のソリッドオブジェクトに適しています。|
|Cutout(カットアウト)| 不透明領域と透明領域の間にハードエッジがある透明効果を作成できます。このモードでは、半透明のエリアはなく、テクスチャは100％不透明、または不可視になります。このモードは、透明度を利用して植生などの素材の形状を作成する場合に便利です。|
|Fade(フェード)| 透明度の値でオブジェクトを完全にフェードアウトさせることができ、それにはスペキュラーハイライトや反射も含まれます。このモードは、オブジェクトがフェードイン／アウトする様子をアニメーションで表現したい場合に便利です。透明なプラスチックやガラスなど、リアルな透明素材のレンダリングには適していません。なぜなら、反射やハイライトもフェードアウトしてしまうからです。|
|Transparent(透明)| 透明なプラスチックやガラスなど、リアルな透明素材の表現に適しています。このモードでは、マテリアル自体に透明度の値が適用されます（テクスチャのアルファチャンネルとティントカラーのアルファに基づく）。ただし、反射や照明のハイライトは、実際の透明なマテリアルの場合と同様に、完全な透明度で表示されます。|
|Additive(加算法)| 前のピクセルの色と現在のピクセルの色を加算する、加算法のブレンドモードを有効にします。これは、透明度のソート問題を避けるために推奨される透明度モードです。|
|Custom(カスタム)| レンダリングモードのすべての側面を手動で制御できるようにします。高度な用途にのみ使用できます。|


![220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/50377272-82cd-ea89-e004-8f570a6836b6.png)


|カリングモード| 説明|
|:--|:--|
|Off| フェイスカリングを無効にします。Cullingは、2面のメッシュが必要な場合にのみOffに設定してください。|
|Front| 正面からのカリングを有効にする。|
|Back|（デフォルト） 裏面のカリングを有効にする。レンダリングパフォーマンスを向上させるために、バックフェイスカリングをできるだけ頻繁に有効にする必要があります。|


**パフォーマンス**

Unity標準シェーダと比較してMRTK標準シェーダを使用する主な利点の1つは、パフォーマンスです。MRTK標準シェーダは、有効になっている機能のみを利用するように拡張可能です。しかし、MRTK標準シェーダは、Unity標準シェーダと同等の審美的な結果を、はるかに低いコストで実現するようにも書かれています。シェーダの性能を比較する簡単な方法の1つは、GPU上で実行する必要のある演算の数である。もちろん、有効な機能やその他のレンダリング構成によって演算の大きさは変動します。しかし、一般的には、MRTK標準シェーダはUnity標準シェーダよりも計算量が大幅に少なくなります。

Unity Standardシェーダの統計例

![47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2a3c39c8-03a0-d810-fdd8-e0acc6575b7d.png)


MRTK Standardシェーダの統計情報の例

![167.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e127473e-7450-e7d7-d2d9-52846ac14285.png)

> 注意
> 
> これらの結果は、シェーダーアセットを選択してUnityインスペクタで表示し、「Compile and show code」ボタンをクリックすることで生成できます。


**Lighting**

MRTK/Standardでは、ライティングに簡単な近似値を使用しています。このシェーダは物理的な正しさやエネルギー保存のための計算を行わないため、迅速かつ効率的にレンダリングを行うことができます。Blinn-Phongは主要なライティングテクニックで、フレネルやイメージベースのライティングとブレンドして物理ベースのライティングを近似します。シェーダは以下のライティングテクニックをサポートしています。

**Directional light(方向性のある光)**

シェーダは、シーン内の最初のUnity Directional Lightの方向、色、強度を尊重します（有効な場合）。ダイナミックポイントライト、スポットライト、その他のUnityライトは、リアルタイムのライティングでは考慮されません。

**Spherical harmonics(球面ハーモニクス)**

シェーダはライトプローブを使用して、有効になっていれば球状ハーモニクスを使ってシーン内のライトを近似します。球面調和の計算は、計算コストを削減するために頂点ごとに行われます。

**Lightmapping(ライトマッピング)**

静的なライティングの場合、シェーダはUnityのLightmappingシステムによって構築されたライトマップを尊重します。ライトマップを使用するには、レンダラーをスタティック（またはライトマップスタティック）としてマークするだけです。

**Hover light(ホバーライト)**

関連項目： ホバーライト

**Proximity light(プロキシミティライト)**

プロキシミティライトを見る

**軽量スクリプト可能なレンダーパイプラインのサポート**

MRTKには、開発者がMRTKシェーダーでUnityのLightweight Scriptable Render Pipeline（LWRP）を利用できるようにするためのアップグレードパスが含まれています。Unity 2019.1.1f1およびLightweight RP 5.7.2パッケージでテストされています。または、LWRPを使い始める手順については、このページを参照してください。

MRTKのアップグレードを行うには、以下を選択します。Mixed Reality Toolkit」→「Utilities」→「MRTK Standard Shader for Lightweight Render Pipeline」のアップグレード

![138.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2ecc4901-5522-a678-5118-6da1b1ddc9e0.png)

アップグレードが行われると、MRTK/Standardシェーダーが変更され、マゼンタ（シェーダーエラー）のマテリアルが修正されるはずです。アップグレードが正常に行われたことを確認するには、コンソールで以下を確認してください。Upgraded Assets/MixedRealityToolkit/StandardAssets/Shaders/MixedRealityStandard.shader for use with the Lightweight Render Pipeline.

**UGUIサポート**

MRTK Standardシェーディングシステムは、Unityに組み込まれたUIシステムで動作します。UnityのUIコンポーネントでは、unity_ObjectToWorldマトリックスは、グラフィックコンポーネントが乗っているローカルトランスフォームのトランスフォームマトリックスではなく、その親キャンバスのトランスフォームマトリックスです。多くのMRTK/Standardシェーダーエフェクトは、オブジェクトのスケールを知る必要があります。この問題を解決するために、ScaleMeshEffect.csはUIメッシュの構築時にスケーリング情報をUVチャンネル属性に格納します。

なお、Unity Imageコンポーネントを使用する場合は、Unity UIが余分な頂点を生成しないように、Source Imageに「None (Sprite)」を指定することが推奨されます。

MRTK内のCanvasでは、ScaleMeshEffect.csの追加が必要な場合、プロンプトが表示されます。


![114.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e3f1ef7f-ebac-c826-bb5d-d21b1865b03f.png)

**テクスチャコンバイナー**

Unity Standardのシェーダーのピクセルごとのメタリックとの整合性を高めるために、スムースネス、エミッシブ、オクルージョンの値をすべてチャンネルパッキングで制御できるようになりました。例えば、以下のようになります。


![93.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/087fd21c-1878-d782-e8b6-2ed4b1b0af7d.png)


チャンネルパッキングを使用すると、4つのテクスチャを別々にサンプリングしてメモリにロードするのではなく、1つのテクスチャをサンプリングしてロードするだけで済みます。テクスチャマップをSubstanceやPhotoshopなどのプログラムで書いた場合、以下のようにハンドパックすることができます。


|チャンネル|プロパティ|
|:--|:--|
|レッド|メタリック|
|グリーン|オクルージョン|
|ブルー|発光（グレイスケール)|
|アルファ| スムーズネス|

また、MRTK Texture Combiner Tool を使用することもできます。このツールを開くには、以下を選択します。Mixed Reality Toolkit -> Utilities -> Texture Combiner を選択すると、以下のウィンドウが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0f61ca0e-2af8-250c-9ec7-dcffec174472.png)

![27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/31bfce43-5d55-928b-e7ba-8f731f639661.png)

このウィンドウは、Unity Standard シェーダを選択して "Autopulate from Standard Material" をクリックすることで、自動的に埋められます。また、赤、緑、青、アルファチャンネルごとにテクスチャ（または定数値）を手動で指定することもできます。テクスチャの組み合わせはGPUアクセラレーションで、入力テクスチャをCPUでアクセスする必要はありません。

**追加機能の説明**

以下に、MRTK/Standardシェーダで利用できるいくつかの機能の詳細をご紹介します。

**プリミティブクリッピング**

![94.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/54679dca-e6a9-7c6a-4b54-331dd26ff176.png)

プリミティブのクリッピングを参照

**メッシュアウトライン**

多くのメッシュアウトライン技術は、後処理技術を使って行われます。後処理は素晴らしい品質のアウトラインを提供しますが、多くのMixed Realityデバイスでは法外なコストがかかる場合があります。MRTK/Examples/Demos/StandardShader/Scenes/にあるOutlineExamplesシーンでは、メッシュアウトラインの使用方法を示すシーンがあります。

![141.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6e588608-f6bb-dd26-fda2-a0c71a8264cc.png)

MeshOutline.csとMeshOutlineHierarchy.csは、メッシュレンダラーの周りにアウトラインをレンダリングするために使用できます。このコンポーネントを有効にすると、アウトライン化されているオブジェクトのレンダリングパスが追加されますが、モバイルのMixed Realityデバイス上でパフォーマンスよく動作するように設計されており、ポストプロセスを使用しません。このエフェクトの制限事項としては、防水性のない（または両面が必要な）オブジェクトにはうまく機能しないことや、オーバーラップするオブジェクトに深度のソート問題が発生することなどが挙げられます。

アウトラインビヘイビアは、MRTK/Standardシェーダと組み合わせて使用するように設計されています。アウトラインマテリアルは通常、無彩色のソリッドカラーですが、様々な効果を得るために設定することができます。アウトラインマテリアルのデフォルト設定は以下の通りです。

![145.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/b6cbc8f6-2a4c-92ed-c849-38453ea537c1.png)

1. Depth Write - アウトラインマテリアルでは無効にして、アウトラインが他のオブジェクトのレンダリングを妨げないようにする必要があります。
2. Vertex Extrusion(頂点押し出し) - アウトラインをレンダリングするためには、有効にする必要があります。
3. Smooth Normalsの使用 - この設定は一部のメッシュではオプションです。押し出しは、頂点を頂点法線に沿って移動することで行われますが、一部のメッシュでは、デフォルトの法線に沿って押し出すと、アウトラインに不連続性が生じます。この不連続性を修正するために、このボックスをチェックすると、MeshSmoother.csで生成される別の平滑化された法線を使用することができます。

MeshSmoother.csは、メッシュ上にスムージングされた法線を自動的に生成するために使用できるコンポーネントです。このメソッドは、空間内で同じ場所を共有するメッシュの頂点をグループ化し、それらの頂点の法線を平均化します。このプロセスでは、基礎となるメッシュのコピーが作成されるため、必要な場合にのみ使用する必要があります。

![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2bbba770-deaf-5dd2-d1b9-1ac5b9867f0d.png)

1. MeshSmoother.csで生成された滑らかな法線。
2. デフォルトの法線が使用されており、立方体の角にはアーチファクトが見られる。

**ステンシルテスト**

設定可能なステンシルテストが組み込まれており、様々な効果を得ることができます。ポータルのようなものです。

![123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/063d2e16-95f4-c089-5392-901aa8dca545.png)

**インスタンスカラーサポート**

何千ものGPUインスタンス化されたメッシュに独自のマテリアル・プロパティを与えるインスタンス・カラー・サポート。

![213.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a9dd2633-26fa-f118-a42b-56c81cce7428.png)

**トリプラナーマッピング**

トリプラナーマッピングは、プログラムでメッシュにテクスチャを施す手法です。地形、UVのないメッシュ、アンラップの難しい形状などによく使われます。この実装では、ワールドまたはローカルスペースプロジェクション、ブレンディングスムースネスの指定、法線マップのサポートをサポートしています。ただし、使用される各テクスチャには3つのテクスチャサンプルが必要なので、パフォーマンスが重要な場面では控えめに使用してください。

![42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f6360287-4ec7-5570-7675-4d0e54126655.png)

**頂点押し出し**

ワールドスペースでの頂点押し出し。押し出されたバウンディングボリュームやメッシュ内外のトランジションを視覚化するのに便利です。

![38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f9102daa-c348-9404-b75c-809ff123a382.png)

**その他**

アルベドの最適化を制御するためのチェックボックスです。アルベドの最適化として、アルベドテクスチャが指定されていない場合、アルベド操作は無効になります。これは、リモートテクスチャのロードを制御するのに便利です。

単にこのボックスをチェックするだけです。

![259.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0cfbedd0-85e0-79e6-4f49-b364b42e42a1.png)

ピクセルごとのクリッピングテクスチャー、ローカルエッジベースのアンチエイリアシング、法線マップのスケーリングがサポートされています。

![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/89f8eec0-90f4-7b2d-14db-a4ce2a4bf632.png)


# Hand menu

![204.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6d3121d5-bda5-9e98-1bfb-49d9726fbeea.png)

ハンドメニューは、ユーザーが頻繁に使用する機能のために、手に装着されたUIを素早く呼び出すことができます。ハンドメニューには、他のオブジェクトとのインタラクション時の誤作動を防ぐために、「平らな手を必要とする」や「注視機能を使用する」などのオプションが用意されています。これらのオプションを使用して、不要な起動を防ぐことをお勧めします。

**ハンドメニューの例**

MRTK/Examples/Demos/HandTracking/Scenesフォルダに、HandMenuExamples.unityシーンがあります。このシーンを実行すると、現在選択されているメニュータイプのみがアクティブになります。

![155.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d0c2c91f-736b-0976-dccb-6d813ce27987.png)

MRTK/Examples/Demos/HandTracking/Prefabsフォルダに、これらのハンドメニュープレハブがあります。

**HandMenu_Small_HideOnHandDrop と HandMenu_Medium_HideOnHandDrop**

これらの2つの例は、MenuContentオブジェクトをアクティブにしたり非アクティブにしたりするだけで、OnFirstHandDetected()イベントやOnLastHandLost()イベントでメニューを表示したり隠したりすることができます。

![63.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/ea704b37-03ea-07f5-fc1a-fcbd47a41fc6.png)

![108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f7efde70-bc8c-5342-6c57-4b30cb1927ff.png)

**HandMenu_Large_WorldLock_On_GrabAndPull**

より複雑なメニューで、より長いインタラクション時間を必要とする場合は、メニューをワールドロックすることをお勧めします。この例では、OnFirstHandDetected()イベントとOnLastHandLost()イベントでMenuContentを有効にしたり無効にしたりすることに加えて、ユーザーがメニューを掴んだり引っ張ったりすることで、メニューをワールドロックします。

![26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e708f346-8d7c-b1f9-faba-d5dffc01e7dd.png)

バックプレートのManipulationHandlerで、掴んだり動かしたりできるようにしています。Manipulation Startedイベントでは、SolverHandler.UpdateSolversを非アクティブにして、メニューをワールドロックしています。さらに、Closeボタンを表示して、タスクが終了したときにメニューを閉じることができるようにします。Manipulation Endedイベントでは、HandConstraintPalmUp.StartWorldLockReattachCheckCoroutineを呼び出し、ユーザーが手のひらを上げて見ることで、メニューを手元に戻せるようにしています。

![83.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c6796c6e-6bdd-3c13-1108-695160a7bba4.png)

閉じるボタンを押すと、SolverHandler.UpdateSolversが起動し、MenuContentが隠れます。

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/6ef4cee8-433b-b3fe-26c9-b6ce78f7b9ce.png)


**HandMenu_Large_AutoWorldLock_On_HandDrop**

この例は、HandMenu_Large_WorldLock_On_GrabAndPullと似ています。唯一の違いは、ハンドドロップで自動的にワールドロックされることです。これは、OnLastHandLost()イベントでMenuContentを非表示にしないだけで行われます。掴んで引っ張る動作は、HandMenu_Large_WorldLock_On_GrabAndPullの例と同じです。

**スクリプト**

HandConstraintビヘイビアは、ハンドコンストレイントコンテンツ（ハンドUI、メニューなど）にとって安全な領域にトラッキングオブジェクトをコンストレイントするソルバーを提供します。安全な領域とは、手と交差しない領域と考えられます。HandConstraintPalmUpというHandConstraintの派生クラスも含まれており、手のひらがユーザーに向いているときにソルバーの追跡オブジェクトをアクティブにするという一般的な動作を示しています。

詳しい説明は、各HandConstraintのプロパティに用意されているツールチップをご覧ください。いくつかのプロパティについては、以下に詳しく説明します。


![159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/3983f6a4-c51e-2fc0-4982-05f9901efd03.png)

- Safe Zone(セーフゾーン)： セーフゾーンは、コンテンツを手のどこに配置するかを指定します。手との重なりを避け、インタラクションの質を向上させるために、コンテンツを尺側に配置することを推奨します。セーフゾーンは、手の向きをカメラのビューに直交する平面に投影し、手の周囲のバウンディングボックスに対してレイキャスティングすることで算出されます。セーフゾーンは、IMixedRealityHandで動作するように定義されていますが、他のコントローラタイプでも動作します。それぞれのセーフゾーンがどのような意味を持つのか、異なるコントローラタイプで調べてみることをお勧めします。

- Follow Hand Until Facing Camera (カメラに向くまで手を追う) ： この機能を有効にすると、ソルバーはメニューが視線と十分に一致するまで手の回転に追従し、その時点でカメラに向くようになります。これは、HandConstraintSolverのSolverRotationBehaviorをLookAtTrackedObjectからLookAtMainCameraに変更することで、ソルバーとのGazeAlignmentの角度が変わることで動作します。

![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8c4ad601-9999-c581-327d-696bded91e26.png)

- Activation Events: 現在、HandConstraintは4つのアクティベーションイベントをトリガーします。これらのイベントは、ユニークなHandConstraintのビヘイビアを作成するために多くの異なる組み合わせで使用することができます。これらのビヘイビアの例については、MRTK/Examples/Demos/HandTracking/Scenes/にあるHandBasedMenuExampleシーンを参照してください。
  - OnHandActivate：ハンドが IsHandActive メソッドを満たすときにトリガーします。
  - OnHandDeactivate：IsHandActive メソッドが満たされなくなったときにトリガーされます。
  - OnFirstHandDetected：ハンド トラッキング ステートが、ビュー内のハンドがない状態からビュー内の最初のハンドに変わったときに発生します。
  - OnLastHandLost: ハンドトラッキングの状態が、ビュー内の少なくとも 1 つのハンドからビュー内のハンドがない状態に変化したときに発生します。

- ソルバーのアクティブ化/非アクティブ化ロジック: 現在、HandConstraintPalmUpロジックをアクティブにしたり非アクティブにしたりするための推奨事項は、オブジェクトを無効にしたり有効にしたりするのではなく、SolverHandlerのUpdateSolver値を使用して行うことです。これは、サンプルシーンでは、付属メニューのManipulationHandlerの「OnManipulationStarted/Ended」イベントの後にトリガーされるエディタベースのフックを通して見ることができます。
  - hand-constraint logicの停止。ハンドコンストレイントオブジェクトを停止するように設定しようとする場合 (アクティベーション/ディアクティベーションロジックを実行しないようにする場合も同様)、HandConstraintPalmUpを無効にするのではなく、UpdateSolverをFalseに設定します。
    - 視線ベースの(または非視線ベースの)再装着ロジックを有効にしたい場合は、これに続いて、HandConstraintPalmUp.StartWorldLockReattachCheckCoroutine()関数を呼び出します。これにより、「IsValidController」の基準が満たされているかどうかをチェックし続けるコルーチンが起動し、満たされている（またはオブジェクトが無効になっている）場合は、UpdateSolverをTrueに設定します。
  - hand-constraint logicの開始。手の拘束されたオブジェクトが再び手を追いかけ始めるように設定しようとするとき（起動基準を満たしているかどうかに基づいて）、SolverHandlerのUpdateSolverをTrueに設定します。
- Reattach Logic(再接続ロジック): 現在、HandConstraintPalmUpは、SolverHandlerのUpdateSolverがTrueであるかどうかにかかわらず、ターゲットオブジェクトを追跡されたポイントに自動的に再アタッチすることができます。これは、ワールドロックされた後に、HandConstraintPalmUpのStartWorldLockReattachCheckCoroutine()関数を呼び出すことで行われます（この場合、SolverHandlerのUpdateSolverを事実上Falseに設定しています）。




# App bar

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1cc3df94-cbe1-8318-a37d-ceab0a9bfdf2.png)


App barは、バウンドコントロールスクリプトと一緒に使用されるUIコンポーネントです。ボタンコントロールをオブジェクトに追加し、オブジェクトを操作することを意図している。Adjust」ボタンを使用すると、オブジェクトのバウンズコントロールインターフェースを解除/有効にすることができる。Removeボタンを使うと、オブジェクトをシーンから削除することができます。

**アプリバーの使い方**

AppBar（Assets/MRTK/SDK/Features/UX/Prefabs/AppBar/AppBar.prefab）をシーン階層にドラッグ＆ドロップしてください。コンポーネントのインスペクタパネルで、バウンズコントロールを持つ任意のオブジェクトをTarget Bounding Boxとして割り当て、そこにアプリバーを追加します。

重要：ターゲットオブジェクトのバウンズコントロール有効化オプションは「Activate Manually」にしてください。

![35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4f929387-3c27-6b52-0dc9-d68f5ebd4cb5.png)


![239.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/df1c4fe8-e65b-c8d6-bea2-a3e642dccae9.png)

# Pointers

![216.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0b916cd9-5abd-ab0e-b914-31197067ac40.png)


この記事では、Pointer Architectureと比較して、実際にPointer入力をどのように構成し、どのように応答するかを説明します。

ポインターは、新しいコントローラが検出されると、ランタイムに自動的にインスタンス化されます。1つのコントローラーに複数のポインターを付けることができます。たとえば、デフォルトのポインタープロファイルでは、Windows Mixed Realityコントローラは、通常の選択とテレポートのために、それぞれラインポインターとパラボリックポインターの両方を得ることができます。

**ポインターの設定**

ポインターは、MRTKの入力システムの一部として、MixedRealityPointerProfileを介して構成されます。このタイプのプロファイルは、MRTK ConfigurationインスペクタのMixedRealityInputSystemProfileに割り当てられます。Pointer プロファイルは、カーソル、ランタイムに利用可能な Pointers のタイプ、およびそれらの Pointers が相互に通信してどれがアクティブであるかを決定する方法を決定します。

- Pointing Extent - PointerがGameObjectとインタラクトできる最大の距離を定義します。

- Pointing Raycast Layer Masks - どのPointerがどのGameObjectとインタラクトできるか、どの順番でインタラクトするかを決めるための、優先順位をつけたLayerMaskの配列です。これは、Pointerが他のシーンオブジェクトよりも先にUI要素とインタラクトすることを保証するのに役立ちます。


![264.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/ecc727a3-0a4c-59e9-4311-9c73a8274be3.png)

**Pointerオプションの設定**

MRTK Pointer Profile のデフォルトの構成には、以下のポインタークラスと関連するプレハブがそのまま含まれています。ランタイムにシステムが利用できるポインターのリストは、Pointer ProfileのPointer Optionsで定義されます。開発者はこのリストを利用して、既存のポインターの再構成、新しいポインターの追加、または削除を行うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1e7eb331-9c5a-076b-954c-8c30d84b1142.png)

各Pointerエントリは、以下のデータセットによって定義されます。

- Controller Type - ポインタが有効なコントローラのセット。
  - 例えば、PokePointerは、指でオブジェクトを「突く」役割を果たし、デフォルトでは、多関節ハンドコントローラタイプのみをサポートするとマークされています。ポインターは、コントローラが利用可能になったときにのみインスタンス化され、特にコントローラタイプは、このポインターのプレハブを作成できるコントローラを定義します。
- Handedness - 特定の手（左/右）に対してのみポインターをインスタンス化することができます。


> 注意
> 
> PointerエントリーのHandednessプロパティをNoneに設定すると、そのPointerをリストから削除する代わりに、システムからそのPointerを無効にすることができます。


- Pointer Prefab - このプレハブアセットは、指定されたコントローラタイプとハンドネスに一致するコントローラが追跡され始めると、インスタンス化されます。

1つのコントローラに複数のポインターを関連付けることができます。例えば、DefaultHoloLens2InputSystemProfile (Assets/MRTK/SDK/Profiles/HoloLens2/)では、多関節ハンドコントローラは、PokePointer、GrabPointer、DefaultControllerPointer (つまり、手の光線)に関連付けられています。


> 注意
> 
> MRTKはAssets/MRTK/SDK/Features/UX/Prefabs/Pointersにポインタープレハブのセットを提供しています。Assets/MRTK/SDK/Features/UX/Scripts/Pointersにあるポインタースクリプトの一つ、またはIMixedRealityPointerを実装した他のスクリプトを含んでいれば、新しいカスタムプレハブを作ることができます。


**デフォルトのポインター・クラス**

以下のクラスは、上述のデフォルトのMRTK Pointer Profileで定義された、すぐに利用できるMRTKポインターです。Assets/MRTK/SDK/Features/UX/Prefabs/Pointersの下で提供される各ポインター・プレハブには、ポインター・コンポーネントの1つが添付されています。

![137.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e54664a2-6304-6fc7-d0ff-4640d336e29e.png)

## Farのポインター**

**LinePointer**

基本的なポインタークラスである LinePointer は、入力のソース（すなわちコントローラ）からポインター方向に線を引き、この方向へのシングルレイキャストをサポートします。一般的には、ShellHandRayPointerやテレポートポインターなどの子クラスがインスタンス化され、主に共通の機能を提供するこのクラスの代わりに利用されます（テレポートがどこで終わるかを示す線も描かれます）。

Oculus、Vive、Windows Mixed Realityのようなモーションコントローラの場合、回転はコントローラの回転と一致します。HoloLens 2の多関節ハンドのような他のコントローラの場合、回転はシステムが提供するハンドのポインティングポーズと一致します。

![111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e7e8540c-c7a5-5470-2419-19b3071c2ed1.png)

**カーブポインター**

CurvePointerはLinePointerクラスを拡張し、曲線に沿った多段階のレイキャストを可能にします。このベースとなるポインタークラスは、線が一貫して放物線に曲がるテレポーテーションポインターのような曲線のインスタンスに役立ちます。

**シェルハンドレイポインター**

LinePointer を継承した ShellHandRayPointer の実装は、MRTK Pointer Profile のデフォルトとして使用されます。DefaultControllerPointer プレハブは ShellHandRayPointer クラスを実装しています。

**GGVP ポインター**

GGVPポインターは、Gaze/Gesture/Voice（GGV）ポインターとしても知られており、主にGazeとAir TapまたはGazeとvoice Selectのインタラクションによって、HoloLens 1スタイルのルック＆タップインタラクションを実現します。GGVポインターの位置と方向は、頭の位置と回転によって決定されます。

**タッチポインター**

TouchPointerは、Unity Touch入力（タッチスクリーンなど）の操作を担当します。スクリーンをタッチすると、カメラからシーン内の遠くにある可能性のある場所に光線が投射されるため、これらは「遠いインタラクション」です。

**マウスポインター**

MousePointerは、タッチの代わりにマウスを使って、遠くのインタラクションのためのスクリーンからワールドへのレイキャストを行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/11e23ce6-3f74-5392-4c41-6267b2341ea0.png)



> 注意
> 
> マウスのサポートはMRTKではデフォルトでは利用できませんが、MouseDeviceManagerタイプの新しいInput Data ProviderをMRTKの入力プロファイルに追加し、MixedRealityMouseInputProfileをデータプロバイダに割り当てることで有効にすることができます。


## ニアポインター

**PokePointer**

PokePointerは、"near interaction touchable. "をサポートするゲームオブジェクトと対話するために使用されます。UnityUIの場合、このポインターはNearInteractionTouchableUnityUIを探します。PokePointerはSphereCastを使って最も近いタッチ可能な要素を判断し、押せるボタンなどの動力源として使用します。

GameObjectにNearInteractionTouchableコンポーネントを設定する際には、localForwardパラメータがボタンなどのタッチ可能なオブジェクトの正面を向くように設定してください。また、touchableのboundsがtouchableオブジェクトのboundsと一致していることを確認してください。

便利なポケポケのプロパティ

- TouchableDistance: タッチ可能な面がインタラクトできる最大の距離
- Visuals: 指先のビジュアル（デフォルトでは指のリング）のレンダリングに使用されるゲームオブジェクト。
- Line: オプションで、指先からアクティブな入力面までの線を描きます。
- Poke Layer Masks: ポインタがインタラクトできるゲームオブジェクトと、インタラクトを試みる順序を決定するLayerMaskの優先順位付き配列。なお、ポークポインターとインタラクションするためには、ゲームオブジェクトがNearInteractionTouchableコンポーネントを持っている必要があります。

![215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7fe72748-a1bf-b247-ccb6-148bbbe431ad.png)

**SpherePointer（スフィアポインター**

SpherePointerは、UnityEngine.Physics.OverlapSphereを使って、インタラクションのために最も近いNearInteractionGrabbableオブジェクトを特定します。これはManipulationHandlerのような「つかめる」入力に便利です。PokePointer/NearInteractionTouchableの機能ペアと同様に、Sphere Pointerとインタラクションできるようにするには、ゲームオブジェクトにNearInteractionGrabbableスクリプトのコンポーネントが含まれている必要があります。

![104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/103be0cb-bae6-92e8-6f90-f082e804ddaf.png)

Sphere Pointerの便利なプロパティです。

- Sphere Cast Radius: つかみ取り可能なオブジェクトを検索する際に使用する球体の半径です。
- Near Object Margin: オブジェクトがポインターの近くにあるかどうかを検出するために照会する、球体鋳造半径の上の距離。ニアオブジェクトの検出半径の合計は、Sphere Cast Radius + Near Object Margin です。
- Near Object Sector Angle: 近くにあるオブジェクトを検索するための、ポインターの前方軸周りの角度です。IsNearObject クエリを円錐形のように機能させます。Hololens 2の動作に合わせて、デフォルトでは66度に設定されています。


![247.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7eb8ce9b-802e-51de-73d3-70ab696d0d64.png)

- Near Object Smoothing Factor: 近距離物体検出の平滑化係数。Near Object Radiusでオブジェクトが検出されると、Near Object Radius * (1 + Near Object Smoothing Factor)となり、感度を下げてオブジェクトが検出範囲から外れにくくなります。
- Grab Layer Masks - LayerMaskの優先順位付けされた配列で、ポインターがインタラクトできるGameObjectの種類と、インタラクトする順番を決定する。SpherePointerと相互作用するためには、GameObjectもNearInteractionGrabbableを持っていなければならないことに注意。


> 注意
> 
> MRTKが提供するデフォルトのGrabPointerプレハブでは、Spatial Awarenessレイヤーが無効になっています。これは、空間メッシュで球体のオーバーラップクエリを行う際のパフォーマンスへの影響を軽減するためです。GrabPointerプレハブを変更することで有効にすることができます。


- Ignore Colliders Not in FOV - ポインタの近くにあっても、実際には視覚的FOV内にないコライダを無視するかどうかを指定します。これは誤ったグラブを防ぐことができ、グラブ可能なものの近くにいてもそれが見えない場合にハンドレイをオンにすることができます。視覚的FOVは、パフォーマンス上の理由から、一般的なフラクタムの代わりに円錐で定義されます。この円錐は、ディスプレイの高さ（または垂直方向のFOV）の半分に相当する半径で、カメラのフラスタムと同じように中心と方向が定められています。


![190.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5463628d-9a6d-c44b-e3b7-3c324b6a4389.png)

**テレポートポインター**

- TeleportPointer は、ユーザーを移動させるためのアクションが行われたとき (テレポート ボタンが押されたときなど)、テレポート要求を発生させます。
- ParabolicTeleportPointerは、ユーザーを移動させるために放物線のレイキャストでアクションを起こしたとき（つまりテレポートボタンが押されたとき）に、テレポートのリクエストを出します。

![56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c23e45e4-d955-8f76-1900-e984ccc674c8.png)

**mixed realityプラットフォームのポインターサポート**

次の表は、MRTKで一般的なプラットフォームに使用されるポインタータイプの詳細です。注：これらのプラットフォームに異なるポインタタイプを追加することは可能です。例えば、VRにPokeポインターやSphereポインターを追加することができます。さらに、ゲームパッドを搭載したVRデバイスでは、GGVポインタを使用することができます。


|Pointer| OpenVR| Windows Mixed Reality| HoloLens 1| HoloLens 2|
|:--|:--|:--|:--|:--|
|ShellHandRayPointer| 有効|有効||有効|
|TeleportPointer| 有効| 有効|||		
|GGVPPointer||| 有効||	
|SpherePointer|||| 有効|
|PokePointer|||| 有効|


## コードによるポインターのインタラクション

**ポインターイベントインターフェース**

以下のインターフェイスを1つ以上実装し、Colliderを持つGameObjectに割り当てられたMonoBehavioursは、そのインターフェイスで定義されたPointer Interactionイベントを受け取ります。


|イベント|内容| ハンドラ|
|:--|:--|:--|
|Before Focus Changed / Focus Changed| ポインタのフォーカスが変わるたびに、フォーカスを失ったゲームオブジェクトとフォーカスを得たゲームオブジェクトの両方で発生します。|	IMixedRealityFocusChangedHandler|
|Focus Enter / Exit |最初のポインタが入ったときにフォーカスを得るゲームオブジェクトと、最後のポインタが出たときにフォーカスを失うゲームオブジェクトに発生。	|IMixedRealityFocusHandler|
|Pointer Down / Dragged / Up / Clicked |ポインタのプレス、ドラッグ、リリースを報告するために発生する。|	IMixedRealityPointerHandler|
|Touch Started / Updated / Completed |PokePointerのようなタッチ対応のポインターがタッチアクティビティを報告するために上げられます。|	IMixedRealityTouchHandler|


> 注意
> 
> IMixedRealityFocusChangedHandlerとIMixedRealityFocusHandlerは、それらのイベントが発生したオブジェクトで処理されなければなりません。フォーカスイベントをグローバルに受信することは可能ですが、他の入力イベントとは異なり、グローバルイベントハンドラはフォーカスに基づくイベントの受信をブロックしません（イベントはグローバルハンドラとフォーカスされた対応するオブジェクトの両方で受信されます）。

**ポインタ入力イベントの動作**

Pointer入力イベントの動作
ポインタ入力イベントは、通常の入力イベントと同様にMRTKの入力システムで認識・処理されます。違いは、ポインター入力イベントは、入力イベントを発生させたポインターがフォーカスしているGameObjectと、グローバルな入力ハンドラーによってのみ処理されることである。通常の入力イベントは、すべてのアクティブなポインターにフォーカスしているGameObjectによって処理されます。

- MRTKの入力システムは入力イベントが発生したことを認識する
- MRTK入力システムは登録されているすべてのグローバル入力ハンドラに対して、入力イベントに関連するインタフェース関数を起動する。
- 入力システムは、イベントを発生させたポインタがフォーカスされているGameObjectを判断する
  - 入力システムはUnityのイベントシステムを利用して、フォーカスされているGameObject上のすべてのマッチするコンポーネントに関連するインターフェース関数を起動する
  - 入力イベントが「使用済み」と判定された場合、処理は終了し、それ以降のGameObjectはコールバックを受け取らなくなる。
    - 例 IMixedRealityFocusHandlerというインターフェースを実装したコンポーネントが、GameObjectがフォーカスを得たり失ったりしたときに検索される。
    - Note: Unity Event Systemは、現在のGameObjectに該当するインターフェイスのコンポーネントが見つからない場合、親となるGameObjectを検索するようにバブルアップする。
- グローバルな入力ハンドラが登録されておらず、一致するコンポーネントやインターフェースを持つGameObjectが見つからない場合、入力システムは登録されている各フォールバックの入力ハンドラを呼び出す。

**例**

ポインタがフォーカスを取ったときや離れたとき、あるいはポインタがオブジェクトを選択したときに、付属のレンダラーの色を変更するスクリプトの例を以下に示す。

```c#
public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler, IMixedRealityPointerHandler
{
    private Color color_IdleState = Color.cyan;
    private Color color_OnHover = Color.white;
    private Color color_OnSelect = Color.blue;
    private Material material;

    private void Awake()
    {
        material = GetComponent<Renderer>().material;
    }

    void IMixedRealityFocusHandler.OnFocusEnter(FocusEventData eventData)
    {
        material.color = color_OnHover;
    }

    void IMixedRealityFocusHandler.OnFocusExit(FocusEventData eventData)
    {
        material.color = color_IdleState;
    }

    void IMixedRealityPointerHandler.OnPointerDown(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerDragged(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
    {
        material.color = color_OnSelect;
    }
}
```

**ポインターの検索**

利用可能な入力ソース（コントローラや利用可能な入力など）をループして、どのポインターが接続されているかを調べることで、現在アクティブなポインターをすべて集めることができます。

```c#
var pointers = new HashSet<IMixedRealityPointer>();

// 全ての有効なポインターを見つける
foreach (var inputSource in CoreServices.InputSystem.DetectedInputSources)
{
    foreach (var pointer in inputSource.Pointers)
    {
        if (pointer.IsInteractionEnabled && !pointers.Contains(pointer))
        {
            pointers.Add(pointer);
        }
    }
}
```

**プライマリポインタ**

開発者は、FocusProvidersのPrimaryPointerChangedイベントをサブスクライブすることで、フォーカスされているプライマリ ポインタが変更されたときに通知を受けることができます。これは、ユーザーが視線やハンドレイなどの入力ソースを使ってシーンを操作しているかどうかを確認するのに非常に役立ちます。

```c#
private void OnEnable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.SubscribeToPrimaryPointerChanged(OnPrimaryPointerChanged, true);
}

private void OnPrimaryPointerChanged(IMixedRealityPointer oldPointer, IMixedRealityPointer newPointer)
{
    ...
}

private void OnDisable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.UnsubscribeFromPrimaryPointerChanged(OnPrimaryPointerChanged);

    //これにより、現在のプライマリポインタが消去されます。
    OnPrimaryPointerChanged(null, null);
}
```


PrimaryPointerExample (Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) のシーンでは、PrimaryPointerChangedHandler をイベントに使用して、新しい primary pointer に対応する方法を示しています。

![102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/694ac45c-d924-41ec-5349-0ac850312a8b.png)

**ポインター result**

ポインタ Result プロパティには、フォーカスのあるオブジェクトを決定するために使用されるシーン クエリの現在の結果が含まれます。モーション コントローラ、視線入力、手の光線のためにデフォルトで作成されるようなレイキャスト ポインターの場合、ヒットしたレイキャストの位置と法線が格納されます。


```c#
private void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
{
    var result = eventData.Pointer.Result;
    var spawnPosition = result.Details.Point;
    var spawnRotation = Quaternion.LookRotation(result.Details.Normal);
    Instantiate(MyPrefab, spawnPosition, spawnRotation);
}
```

PointerResultExampleシーン（Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity）では、ポインターResultを使って、ヒットした場所にオブジェクトをスポーンする方法を紹介しています。

![212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d4269844-a7be-a1dd-c456-858ca6b859be.png)

**ポインタの無効化**

ポインターを有効にしたり無効にしたりするには（例えば、ハンドレイを無効にするには）、PointerUtils を通じて、指定されたポインタータイプの PointerBehavior を設定します。

```c#
// ハンドレイを無効にする
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

// 右手だけのハンドレイを無効にする
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);

// 視線ポインタを無効にする
PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOff);

// HoloLens 1 に合わせて動作を設定します。
// 注意、HoloLens 2の場合は、多関節の手にGGVポインターが表示されるようにポインターのプロファイルを設定する必要があります。
public void SetHoloLens1()
{
    PointerUtils.SetPokePointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGrabPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGGVBehavior(PointerBehavior.Default);
}
```

詳しい例は PointerUtils と TurnPointersOnOff を参照してください。

**エディタによるポインターのインタラクション**

IMixedRealityPointerHandlerによって処理されるポインターイベントに対して、MRTKはPointerHandlerコンポーネントの形でさらなる利便性を提供し、ポインターイベントをUnity Events経由で直接処理することができます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/63d06ee2-d8e4-4eed-86e5-3ad84b79cd15.png)


**ポインターの範囲**

Farポインターには、レイキャストしてシーン内の他のオブジェクトと相互作用する距離を制限する設定があります。デフォルトでは、この値は10mに設定されています。この値は、HoloLens シェルの動作と一致するように選択されています。

これは、DefaultControllerPointerプレハブのShellHandRayPointerコンポーネントのフィールドを更新することで変更できます。

Pointer Extent - ポインターが相互作用する最大距離を制御します。

Default Pointer Extent - これは、ポインターが何も操作していないときにレンダリングされるポインターレイ/ラインの長さをコントロールします。





# Fingertip visualization

![248.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/2d54a38c-f128-2e21-2f7b-d6bb3303979d.png)

指先のアフォーダンスは、ユーザーが対象物からの距離を認識するのに役立ちます。リング形状のビジュアルは、指先から対象物までの距離に応じて大きさを調整します。指先のビジュアライゼーションは、主に、PokePointerのカーソルプレハブとして生成されるFingerCursor（Assets/MRTK/SDK/Features/UX/Prefabs/Cursors/FingerCursor.prefab）（およびスクリプト）によって制御されます。他にも、ProximityLightスクリプトやMixedRealityStandardシェーダーなどが視覚化の構成要素となっています。

**指先のビジュアライゼーションの使用方法**

デフォルトでは、指先の視覚化は、FingerCursorをスポーンするように設定されているUnityのシーンで動作します。FingerCursorのスポーンは、DeltMixedReationTolktConfigurationProfileの下で行われます。

DefaultMixedRealityInputSystemProfile > DefaultMixedRealityInputPointerProfile > PokePointer > FingerCursor。

指先の視覚化は、近接ライトを使用して、近接ライトを受け入れる近くのサーフェスにカラー グラデーションを投影することで動作します。指カーソルは、親のIMixedRealityNearPointerによって決定される、近くにある対話可能なサーフェスを探し、指がサーフェスに向かって移動するときに、指リングをサーフェスに合わせます。指がサーフェスに近づくと、フィンガーリングは、MixedRealityStandardシェーダのラウンドコーナープロパティを使って、ダイナミックにアニメーションします。

**シーン例**

指先のビジュアライゼーションの例は、多関節の手を扱うほとんどのシーンで見ることができますが、HandInteractionExampleシーンでは顕著です。

![146.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/a4130952-48c9-1efe-84d5-53626ed554da.png)

**インスペクタのプロパティ**

FingerCursor フィンガーカーソルのプロパティの多くは、ベースとなるカーソルクラスから継承されています。重要なプロパティには、MixedRealityStandardシェーダのフィンガーリング・アニメーションを駆動する遠近面のマージンと幅があります。その他のプロパティについては、インスペクタのツールチップにカーソルを合わせてください。

![185.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7ae29410-76a4-4243-3218-c49e5e378a75.png)

近接光（ProximityLight） 近接光の設定は、サーフェスに近づいたときと遠ざかったときの光の見え方を制御します。中央、中央、外側の各色はライトのグラデーションを制御し、アプリケーションのカラーパレットに合わせてカスタマイズできます。なお、これらの色はHDR（ハイダイナミックレンジ）で、近接照明を1以上の値に明るくすることができます。その他のプロパティについては、インスペクタのツールチップにカーソルを合わせてください。

MixedRealityStandardシェーダ MixedRealityStandardシェーダは、MRTKの多くのエフェクトに使用されます。指先の視覚化に重要な2つの設定は、"Near Fade "と "Proximity Light "です。ニアフェードは、カメラやライトがオブジェクトに近づくと、オブジェクトがフェードイン／アウトする機能です。カメラではなく近接ライトでフェードさせる場合は、必ず「ライト」をチェックしてください。フェード開始 "と "フェード完了 "の値を逆にすることで、フェードを反転させることができます。近接照明を明るくしたい面には、「近接照明」をチェックします。その他のプロパティについては、インスペクタのツールチップにカーソルを合わせてください。

![177.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/ae662987-d264-228d-4497-dccc3042f3a7.png)


# Near menu

![202.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4dfd8efc-bd15-f455-a544-6d08460712d0.png)


ニアメニューは、ボタンやその他のUIコンポーネントの集合体を提供するUXコントロールです。ニアメニューは、ユーザーの体の周りに浮かび、いつでも簡単にアクセスできます。ユーザーとは疎結合なので、ユーザーと対象コンテンツとの対話を妨げることはありません。ユーザーは「Pin」ボタンを使って、メニューをワールドロック／アンロックすることができます。また、メニューを掴んで特定の位置に配置することも可能です。

**Interaction behavior(インタラクション動作)**

- Tag-along: メニューはユーザーに付いてきて、ユーザーから30～60cmの範囲に留まり、近距離でのインタラクションを行います。
- Pin：「Pin」ボタンを使って、メニューをワールドロックしたり、解除したりすることができます。
- Grab and move(掴んで移動): メニューは常に掴んだり動かしたりすることができます。前の状態に関わらず、掴んで離すとメニューは固定されます（ワールドロック）。掴むことができるエリアには視覚的な手がかりがあります。これらは手の近さでわかります。

![44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/73f20686-c456-f8dd-abcb-fdc9c6aff224.png)


**Prefabs**

ニアメニューのプレハブは、MRTKの様々なコンポーネントを使ってニア・インタラクション用のメニューを構築する方法を示すために設計されています。

- NearMenu2x4.prefab
- NearMenu3x1.prefab
- NearMenu3x2.prefab
- NearMenu3x3.prefab
- NearMenu4x1.prefab
- NearMenu4x2.prefab

**シーン例**

NearMenuExamples シーンでは、「Near Menu」プレハブの例を見ることができます。

![195.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c10697b5-1144-6922-a5a1-71c894e36b21.png)


**Structure(構造)**

ニアメニューのプレハブは、以下のMRTKコンポーネントで構成されています。

- PressableButtonHoloLens2 プレハブ
- Grid Object Collection: 複数のボタンをグリッドに配置
- Manipulation Handler: メニューを掴んで動かす
- Manipulation Handler: Follow Me(tag-along)動作


![161.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c849d66a-d60d-b9a8-25ad-1a33d4dabe73.png)

**カスタマイズ方法**

1. ボタンの追加・削除

ButtonCollectionオブジェクトの下に、ボタンを追加・削除します。

![61.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/08497407-50d2-68d8-b8cf-1af0964addcb.png)

2. グリッドオブジェクトのコレクションの更新

ButtonCollection オブジェクトのインスペクタにある Update Collection ボタンをクリックします。グリッドのレイアウトが更新されます。

![199.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fa47c06e-b9f9-ab85-37ce-33dbcb94320b.png)

グリッドオブジェクトコレクションのRowsプロパティで行数を設定することができます。

![178.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/c54b1a9e-8a70-b39c-c427-ede52b5a70ec.png)

3. バックプレートのサイズ調整

Backplateオブジェクトの下にあるQuadのサイズを調整します。バックプレートの幅と高さは、0.032 * [ボタンの数 + 1]とします。例えば、ボタンの数が3×2の場合、バックプレートの幅は0.032 * 4、高さは0.032 * 3となります。 この式をUnityのフィールドに直接入れることができます。


![245.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/576e0c61-9a84-7188-fab5-21274e92ccf1.png)

HoloLens 2のボタンのデフォルトサイズは3.2x3.2cm（0.032m



# Spatial Awareness(空間認識能力)

![36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fd859ab3-ea9d-db95-ea13-9d61c0325783.png)

Spatial Awarenessシステムは、Mixed Realityアプリケーションで現実世界の環境認識を提供します。Microsoft HoloLensに導入されたSpatial Awarenessは、環境のジオメトリを表すメッシュのコレクションを提供し、ホログラムと現実世界の間の魅力的なインタラクションを可能にしました。


> 注意
> 
> 現時点では、Mixed Reality Toolkitには、HoloToolkitに当初パッケージされていたSpatial Understandingアルゴリズムは搭載されていません。Spatial Understandingでは、通常、Spatial Meshデータを変換して、平面、壁、床、天井などの簡略化されたMeshデータやグループ化されたMeshデータを作成します。


**開始方法**

Spatial Awarenessのサポートを追加するには、Mixed Reality Toolkitの2つの重要なコンポーネント、すなわちSpatial Awarenessシステムと、サポートされているプラットフォーム・プロバイダーが必要です。

1. Spatial Awarenessシステムの有効化
2. メッシュ・データを提供する1つまたは複数の空間オブザーバーを登録および構成
3. Spatial Awarenessをサポートするプラットフォームを構築し、デプロイする。

**Spatial Awarenessシステムの有効化**

Spatial Awarenessシステムは、MixedRealityToolkitオブジェクト（または他のサービス登録コンポーネント）によって管理されます。以下の手順に従って、MixedRealityToolkitプロファイルでSpatial Awarenessシステムを有効または無効にしてください。

Mixed Reality Toolkitには、いくつかのデフォルトの設定済みプロファイルが同梱されています。その中には、空間認識システムがデフォルトで有効または無効になっているものがあります。この事前設定の意図は、特に無効の場合、メッシュの計算とレンダリングによる視覚的なオーバーヘッドを避けることにあります。


|プロファイル | システムをデフォルトで有効にする|
|:--|:--|
|DefaultHoloLens1ConfigurationProfile (Assets/MRTK/SDK/Profiles/HoloLens1) | False|
|DefaultHoloLens2ConfigurationProfile (Ats/MRTK/SDK/Profiles/HoloLens2) |False |
|DefaultMixedRealityToolkitConfigurationProfile (Ats/MRTK/SDK/Profiles) | True |

- シーン階層のMixedRealityToolkitオブジェクトを選択して、インスペクタパネルで開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/e393522f-6073-3248-0a09-1920e61381b0.png)


- Spatial Awareness System」セクションに移動し、「Enable Spatial Awareness System」をチェックします。
- 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/3adbc02f-512f-7395-836b-05fcf6011c18.png)


- 希望するSpatial Awarenessシステムの実装タイプを選択します。MixedRealitySpatialAwarenessSystemがデフォルトで提供されています。



![206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/743a60e6-bef9-d3c3-f5ca-ededbd05e8c8.png)

**オブザーバーの登録**

Mixed Reality Toolkitのサービスには、プラットフォーム固有のデータや実装制御でメイン・サービスを補完するデータ・プロバイダ・サービスがあります。この例として、Mixed Reality入力システム（Mixed Reality Input System）があります。このシステムには、コントローラやその他の関連入力情報をさまざまなプラットフォーム固有のAPIから取得する複数のデータ・プロバイダがあります。

Spatial Awarenessシステムは、データ・プロバイダーが現実世界に関するメッシュ・データをシステムに提供する点で類似している。Spatial Awarenessプロファイルには、少なくとも1つのSpatial Observerが登録されている必要があります。Spatial Observerは通常、プラットフォーム固有のコンポーネントであり、プラットフォーム固有のエンドポイント（HoloLensなど）からさまざまな種類のメッシュデータを表示するためのプロバイダーとして機能します。

- Spatial Awareness Systemプロファイルを開くか展開します。


![193.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8f419075-7f24-0759-aa80-52ce281e8f26.png)


- Add Spatial Observer」ボタンをクリックします。
- 必要なSpatial Observerの実装タイプを選択


![128.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/7dd5325a-8e16-9ace-ef24-591ff182d51a.png)

- 必要に応じてオブザーバーの構成プロパティを変更する


> 注意
> 
> DefaultMixedRealityToolkitConfigurationProfile（Assets/MRTK/SDK/Profiles）を使用すると、WindowsMixedRealitySpatialMeshObserverクラスを使用するWindows Mixed Realityプラットフォーム用のSpatial Awarenessシステムがあらかじめ構成されます。


**ビルドとデプロイ**

空間認識システムに必要なオブザーバーを設定したら、プロジェクトをビルドしてターゲット・プラットフォームにデプロイします。


> 重要
> 
> Windows Mixed Realityプラットフォーム（例：HoloLens）をターゲットとする場合、デバイス上の空間認識システムを使用するために、Spatial Perceptionケイパビリティが有効になっていることを確認することが重要です。



> 警告
> 
> Microsoft HoloLensをはじめとする一部のプラットフォームでは、Unity内からのリモート実行に対応しています。この機能により、ビルドとデプロイのステップを必要とせず、迅速な開発とテストが可能になります。最終的な受け入れテストは、ターゲットとなるハードウェアとプラットフォーム上で実行される、ビルドおよびデプロイされたバージョンのアプリケーションを使用して行うようにしてください。


**次のステップ**
上記の手順で空間認識システムを有効にした後、システムをより詳細に設定および制御することができます。

InspectorでObserversを設定するための情報です。

- デバイス上で使用するオブザーバーの設定
- エディター内で使用するためのオブザーバーの設定

コードでオブザーバーを制御、拡張するための情報。

- コードによるオブザーバーの設定
- カスタムObserverの作成






# Speech

![187.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/017d4ce5-d26c-7b0f-2b32-96a9328e5af4.png)

Windows Speech Inputのような音声入力プロバイダは、コントローラを作成せず、認識されたときに音声入力イベントを発生させるキーワードを定義することができます。入力システムプロファイル」の「音声コマンドプロファイル」で、認識するキーワードを設定します。各コマンドについては、以下のことができます。

- マップする入力アクションを選択します。例えば、キーワード「選択」をマウスの左クリックと同じアクションにマッピングすることで、同じ効果を得ることができます。
- 押されたときに同じ音声イベントを発生させるキーコードを指定する。
- UWPアプリで使用されるローカライズキーを追加し、アプリのリソースからローカライズされたキーワードを取得します。

![92.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/5753a7e6-bb1a-7189-8b6b-4f94176250e3.png)


## 音声入力の処理
Speech Input HandlerスクリプトをGameObjectに追加することで、UnityEventsを使ってスピーチコマンドを扱うことができます。Speech Commands Profileで定義されたキーワードのリストを自動的に表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/4b11dee8-0560-253b-d442-5956abc58afb.png)


オプションのSpeechConfirmationTooltip.prefabを割り当てて、認識時に確認用のツールチップラベルをアニメーションで表示します。


![174.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/bcd1fafa-92f5-7476-b939-06c338687536.png)

また、開発者は、カスタムスクリプトコンポーネントにIMixedRealitySpeechHandlerインターフェイスを実装して、音声入力イベントを処理することもできます。

**サンプルシーン**

MRTK/Examples/Demos/Input/Scenes/SpeechにあるSpeechInputExampleシーンは、スピーチの使用方法を示しています。また、IMixedRealitySpeechHandlerを実装することで、独自のスクリプトでスピーチコマンドイベントを直接聞くことができます（イベントハンドラの表を参照）。

![200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/1aa333b2-26f0-027f-e005-06228dbaa4a3.png)

# Progress Indicators

![192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/624b5899-b840-bb0a-5a02-4cf24673f490.png)

**サンプルシーン**

プログレス インジケータの使用例は、ProgressIndicatorExamples シーンでご覧いただけます。このシーンでは、SDKに含まれているプログレスインジケータの各プレハブを実演しています。

![150.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/bb2eb1c0-4ba1-6930-f826-0d0a0d51d905.png)

**例: プログレス インジケータを開く、更新する、閉じる**

プログレス インジケータは、IProgressIndicator インターフェイスを実装しています。このインターフェースは、GetComponentを使ってGameObjectから取得することができます。

```c#
[SerializedField]
private GameObject indicatorObject;
private IProgressIndicator indicator;

private void Start()
{
    indicator = indicatorObject.GetComponent<IProgressIndicator>();
}
```

IProgressIndicator.OpenAsync()メソッドとIProgressIndicator.CloseAsync()メソッドは、Taskを返します。これらのTaskは、非同期メソッドで待機させることをお勧めします。

インジケータのProgressプロパティに0～1の値を設定して、表示される進捗状況を更新します。表示されているメッセージを更新するには、その Message プロパティを設定します。実装によって、この内容の表示方法が異なる場合があります。

```c#
private async void OpenProgressIndicator()
{
    await indicator.OpenAsync();

    float progress = 0;
    while (progress < 1)
    {
        progress += Time.deltaTime;
        indicator.Message = "Loading...";
        indicator.Progress = progress;
        await Task.Yield();
    }

    await indicator.CloseAsync();
}
```

**インジケータの状態**

インジケータのStateプロパティは、どの操作が有効であるかを決定します。無効なメソッドを呼び出すと、通常、インジケータはエラーを報告し、何のアクションも起こしません。

| 状態 |有効な操作|
|:--|:--|
|ProgressIndicatorState.Open| AwaitTransitionAsync()|
|ProgressIndicatorState.Open| CloseAsync()|
|ProgressIndicatorState.Closing| AwaitTransitionAsync()|
|ProgressIndicatorState.Closed| OpenAsync()|

AwaitTransitionAsync()は、インジケーターを使用する前に、インジケーターが完全に開いているか閉じているかを確認するために使用できます。

```c#
private async void ToggleIndicator(IProgressIndicator indicator)
{
    await indicator.AwaitTransitionAsync();

    switch (indicator.State)
    {
        case ProgressIndicatorState.Closed:
            await indicator.OpenAsync();
            break;

        case ProgressIndicatorState.Open:
            await indicator.CloseAsync();
            break;
        }
    }
```

# Dialog

![221.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9c97f3d9-3724-83f2-7483-f435e0e34bee.png)


ダイアログコントロールは、アプリのコンテキスト情報を提供するUIオーバーレイです。多くの場合、ユーザーに何らかのアクションを要求します。重要な情報をユーザーに通知したり、アクションを完了する前に確認や追加情報を要求するためにダイアログを使用します。

**シーン例**

DialogExampleシーンの例は以下の通りです。MRTK/Examples/Demo/UX/Dialog

**Dialogコントロールの使い方**

MRTKには3つのDialogプレハブが用意されています。

- DialogSmall_192x96.prefab
- DialogMedium_192x128.prefab
- DialogLarge_192x192.prefab

新しいダイアログを開くにはDialog.Open()を使います。ダイアログのプレハブ、ボタンの数、タイトルテキスト、メッセージテキスト、配置距離(近いか遠いか)、追加変数を指定します。) ダイアログには、「確認(シングルボタン)」と「選択(2ボタン)」のダイアログオプションがあります。

```c#
public static Dialog Open(GameObject dialogPrefab, DialogButtonType buttons, string title, string message, bool placeForNearInteraction, System.Object variable = null)
```

**OKボタン1つで大きなダイアログを開き、遠いインタラクション範囲（視線、ハンドレイ、モーションコントローラ）に配置する例**

```c#
//確認用ダイアログ、大きい、遠い
//この例は、1つのボタンしかない大きなダイアログを、遠くの対話範囲に配置したものです。
Dialog.Open(DialogPrefabLarge, DialogButtonType.OK, "Confirmation Dialog, Large, Far", "This is an example of a large dialog with only one button, placed at far interaction range", false);
```

**近いインタラクション範囲（直接手を動かす）に配置された、ユーザーへの選択メッセージを含む小さなダイアログを開く例**

```c#
//確認ダイアログ、小さい、近い
//選択メッセージを含む小さなダイアログを、インタラクション範囲の近くに配置した例です。
Dialog.Open(DialogPrefabSmall, DialogButtonType.Yes | DialogButtonType.No, "Confirmation Dialog, Small, Near", "This is an example of a small dialog with a choice message, placed at near interaction range", true);
```

詳しくは、DialogExample.unityシーンのDialogExampleController.csをご覧ください。

# Hand coach

![107.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/72cb2c92-3273-3f7d-745a-c0a4633cd959.png)

ハンドコーチは、3Dモデル化された手で、システムがユーザーの手を検出できなかったときに起動されます。これは「ティーチング」コンポーネントとして実装されており、ジェスチャーが教えられていないときにユーザーを誘導するのに役立ちます。ユーザーが一定期間、指定されたジェスチャーを行わなかった場合、手は遅延を伴ってループします。ハンドコーチは、ボタンを押したり、ホログラムを拾ったりすることを表現するために使用することができます。

現在のインタラクションモデルでは、スクロール、ファーセレクト、ニアタップなどの多様なジェスチャーコントロールを表現している。以下は、既存のハンドコーチの例の全リストです。

- Near tap - ボタンや近くにあるインタラクティブなオブジェクトに使用される。
- Far select - 遠くにあるオブジェクトに使用される
- Move - ホログラムを空間内で動かすのに使用
- Rotate - ホログラムやオブジェクトを回転させるときに使います。
- Scale - ホログラムを大きくしたり小さくしたりする操作方法を示すために使用します。
- Hand flip(手のひらを返す) - UIスタートパネルや手のひらメニューを表示するときに使用します。
- Palm up(手のひらを上にする) - 箱から出した時に、ハミングバードの瞬間を表現するために使用します。また、UIスタートパネルを表示させることもできます。
- Scroll - リストや長いドキュメントをスクロールするときに使います。

**シーン例**

以下のHandCoachExampleシーンで例を見ることができます。MixedRealityToolkit.Examples/Experimental/HandCoach/Scenes

**ハンド3Dアセット**

以下でアセットを見つけることができます。MixedRealityToolkit.SDK/Experimental/HandCoach

**Quality**

スキニングされたメッシュに歪みが見られる場合は、プロジェクトが適切な量のジョイントを使用しているかどうかを確認する必要があります。UnityのEdit > Project Settings > Quality > Other > Blend Weights を開きます。Smooth Jointsを見るには、「4 bones」が選択されていることを確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/0afddeee-0824-cfec-f3ad-01b29ff2b0c5.png)


**スクリプト**

**インタラクションヒント**

InteractionHint.csスクリプトは、ハンドリグのアニメーションやフェードをトリガーするためのラッパー機能を提供します。

**インタラクションヒントの設定方法**

インタラクションヒントを設定するには、付属のプレハブ「StaticHandCoachRoot_L.prefab」と「StaticHandCoachRoot_R.prefab」を使用することをお勧めします。このプレハブには、InteractionHintスクリプトとハンドリグのほか、適切な階層が含まれており、提供されているヒントアニメーションが意図したとおりに動作するようになっています。そうでない場合は、アニメーターを使ってハンドリグから1つ上の親レベルのゲームオブジェクトにスクリプトを配置する必要があります。

**インスペクタのプロパティ**

- HideIfHandTracked 
  - このブール値は、ユーザーの手がトラッキングされているときに、ビジュアルを隠すためにハンドトラッキングの状態を使用するかどうかを指定します。これを false に設定すると、スクリプトのプロパティ "customShouldHideVisuals" のみを使用してヒントを隠すかどうかを判断します。
- MinDelay 
  - このプロパティは、ビジュアルを表示する際の最小遅延を指定します。デフォルトでは、ユーザーの手が追跡されていない場合、手のビジュアルはこの秒数後に表示されます。
- MaxDelay 
  - このプロパティは、ビジュアルを表示するための最大の遅延を指定します。デフォルトでは、ユーザーの手が追跡されていても、この秒数後に手のビジュアルが表示されます。
- UseMaxTimer 
  - このブール値が false に設定されると、最大タイマーが無効になり、ユーザーの手が見えなくなった時、またはカスタム条件が false を返した時にのみ、手のヒントが表示されるようになります。
- Repeats 
  - このプロパティは、最小または最大タイマーが経過したときに、ヒントアニメーションを何回再生するかをコントロールします。ヒントは非表示になり、再び遅延が発生するのを待ちます。
- AutoActivate
  - このブール値がtrueに設定されていると、スクリプトのGameObjectが階層内でアクティブになっていて、スクリプトが有効になっている場合、ヒントは自動的にタイマーロジックを実行します。ヒントの表示・非表示をコードで手動でコントロールする場合にのみ、falseを設定する必要があります。
- AnimationState 
  - ヒントがアクティブになったときに再生するアニメーションの状態の名前です。StartHintLoop()関数が呼び出される前（AutoActivateがチェックされている場合はOnEnable中）に設定する必要があります。

**スクリプトによるInteractionHintの制御**

- StartHintLoop 
  - この関数は、AutoActivateフラグがtrueに設定されている場合、OnEnableを開始する表示/非表示ループを開始します。
- StopHintLoop 
  - この関数は、現在再生されていない場合、フェードアウトのアニメーション状態を呼び出し、その後、show/hideループを非アクティブにし、階層内のハンドリグを非アクティブにします。
- AnimationState 
  - この文字列は、ループ中にどのアニメーションステートを再生するかを決定します。この文字列を変更して再生する状態を変えることができますが、StopHintLoopを呼び出した後に変更しなければならず、状態を変更した後に再度StartHintLoopを呼び出す必要があります。
- CustomShouldHideVisuals 
  - これは独自の関数で設定することができ、手のビジュアルを隠したいときにはtrueを返す必要があります（MinMaxTimer、特にmaxパラメータに注意してください）。

**カスタムアニメーションの注意点**

フェードはデフォルトで0.5秒に設定されていますので、リグで使用するカスタムアニメーションは、意味のある情報を伝えるために1.5秒以上にする必要があります。

フェードインとフェードアウトのデフォルトの状態であるFade_InとFade_Outは、2つ目のキーフレームのタイムスタンプを変更することで、フェードの長さを設定することができます。

アニメーターとスクリプトは、できるだけ簡単にセットアップができるように設定されています。新しいアニメーションの状態を追加するには、fbxをインポートして、アニメーションの名前が別の名前で設定されていることを確認し、そのアニメーションをアニメーターにドラッグします。

**MoveToTarget**

MoveToTarget.cs スクリプトは、手のひらをトラッキング位置からターゲット位置へと時間をかけて移動させる機能を提供します。

**MoveToTarget の設定方法**

提供されているプレハブ「MovingHandCoachRoot_L.prefab」と「MovingHandCoachRoot_R.prefab」の階層にはMoveToTargetが含まれています。このスクリプトを自分のセットアップで使用する場合は、リグのアニメーターを含むルートゲームオブジェクトに配置する必要があります。

**インスペクタのプロパティ**

- TrackingObject 
  - リグが動き出す前に追従させたいオブジェクトを設定します。空のゲームオブジェクトを作成し、トラッキングを正確に行うために特定の位置に移動させることをお勧めします。
- TargetObject 
  - リグのモーション中に移動させたいオブジェクトを設定します。空のGameObjectを作成し、トラッキングを正確に行うために特定の位置に移動させることをお勧めします。
- RootObject 
  - トラッキングオブジェクトとターゲットオブジェクトの親を共有して、相対的な位置を正しく計算できるようにします。同梱されているプレハブの階層には、トラッキングオブジェクトとターゲットオブジェクトの両方が含まれていますが、プレハブの外でターゲットオブジェクトをゲームオブジェクトとして設定し、ルートオブジェクトを共有する親に変更することができます。
- Duration 
  - TrackingObjectからTargetObjectに移動するのにかかる時間（秒単位）です。
- TargetOffset 
  - GameObjectが正しいターゲット位置に到達するための調整可能なオフセットです。これはアニメーション中に位置のオフセットを含む場合に便利です。
- AnimationCurve 
  - デフォルトでは直線的なカーブに設定されていますが、カーブを変更することで、モーションパスの開始・停止時にイージングイン/アウトを行うことができます。

**スクリプトによるMoveToTargetの制御**

カスタム スクリプトで、ハンド リグが TrackingObject に追従している間に Follow() を呼び出し、ハンド リグが TargetObject に向かって移動を開始するときに MoveToTargetPosition() を呼び出します。

**アニメーションによるMoveToTargetの制御**

動かす必要のあるアニメーションに、Follow()とMoveToTargetPosition()の2つのイベントを設定します。Followは最初のキーフレームで設定します。これによりハンドリグがTrackingObjectを追いかけるようになります。MoveToTargetPositionは、リグをターゲットに移動させたいキーフレームで設定します。このスクリプト機能は、提供されているプレハブで使用されています。

**RotateAroundPoint**

RotateAroundPoint.cs スクリプトは、手のヒントをピボットポイントの周りに時間をかけて回転させる機能を提供します。

**RotateAroundPoint を設定する方法**

提供されているプレハブ「RotatingHandCoachRoot_L.prefab」と「RotatingHandCoachRoot_R.prefab」には、その階層にRotateAroundPointが含まれています。このスクリプトを自分のセットアップで使用したい場合は、リグのアニメーターを含むルートゲームオブジェクトに配置する必要があります。

**インスペクタのプロパティ**

- CenteredParent 
  - リグがピボットする親オブジェクトを設定します。
- InverseParent 
  - 手の向きが変わらないように、centeredParentと逆に回転させる親を設定します。一般的には、InteractionHintスクリプトが置かれた親オブジェクトになります。
- PivotPosition 
  - ヒントの動きを開始させたいポイントを設定します。
- Duration 
  - CenteredParentの周りを回転するのにかかる時間（秒）を設定します。
vAnimationCurve 
    デフォルトでは直線的なカーブに設定されていますが、カーブを変更することで、モーションパスの開始や停止の際に緩和された状態にすることができます。
- RotationVector 
  - 各軸を何度回転させるかを指定します。

**スクリプトによる RotateAroundPoint の制御**

カスタム スクリプトでは、ハンド リグが CenteredParent の周りを回転し始めるときに RotateToTarget() を呼び出します。位置を元の PivotPosition に戻したい場合は、ResetAndDeterminePivot() を呼び出します。

**アニメーションによる RotateAroundPoint の制御**

移動が必要なアニメーションでは、ResetAndDeterminePivot()を呼び出したイベントと、RotateToTarget()を呼び出したイベントの2つを設定します。ResetAndDeterminePivotは、ハンドリグをPivotPositionにリセットするため、最初のキーフレームに設定する必要があります。RotateToTargetは、リグがCenteredParentの周りを回転し始めるようにしたいキーフレームで設定する必要があります。このようなスクリプト機能は、提供されているプレハブで使用されています。




# Hand physics extension services

![255.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fb0d7ace-2c94-21af-051a-98118452dcae.png)

手の物理サービスは、剛体の衝突イベントや、多関節の手とのインタラクションを可能にします。

**ハンドフィジックス エクステンション サービスの使用方法**

ハンドフィジックス サービスを拡張サービスのリストに追加し、デフォルトのプロファイルを使用します。

有効にすると、任意のコライダの IsTrigger プロパティを使用して、10 桁の数字すべて（有効な場合は手のひらも）からのコリジョン イベントを受け取ることができます。

**前提条件**

- 拡張サービスを有効にする。
- 指と手のひらのジョイントに適切なプレハブを割り当てます。

**推奨事項**

このサービスのデフォルトは「デフォルト」レイヤーですが、HandPhysicsオブジェクトには別のレイヤーを使用することをお勧めします。そうしないと、望ましくない衝突や不正確なレイキャストが発生する可能性があります。



# Scrolling object collection


![179.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/067daa54-0ccf-c6c5-040d-357dac47610c.png)

MRTK scrolling object collectionは、3Dコンテンツのスクロールを可能にするUXコンポーネントです。スクロールの動きは、近距離または遠距離の入力インタラクションや、離散的なページネーションによってトリガされます。インタラクティブなオブジェクトと非インタラクティブなオブジェクトの両方をサポートしています。

**スクロールオブジェクトコレクションの使用方法**

**シーンの設定**

- 新しいunityシーンを作成する。
- MRTKをシーンに追加するには、「Mixed Reality Toolkit」 > 「Add to Scene and Configure」を選択します。

**スクロールオブジェクトの設定**

- シーンの中に空のゲームオブジェクトを作成し、その位置を（0, 0, 1）に変更します。
- ゲームオブジェクトにスクローリングオブジェクトコレクションコンポーネントを追加します。
  - スクロールオブジェクトコレクションを追加すると、ルートゲームオブジェクトにボックスコライダとニアインタラクションタッチ可能コンポーネントが自動的にアタッチされます。これらのコンポーネン トにより、スクロールオブジェクトはポインタのタッチやクリックなど、近距離と遠距離のインタラクション 入力イベントをリッスンすることができます。
  - MRTKのスクロールオブジェクトコレクションには、ルートのスクローリングオ ブジェクト階層の下に子ゲームオブジェクトとして作成される、2つの重要な 要素があります。
  - Container - すべてのスクロールコンテンツオブジェクトは、コンテナゲームオ ブジェクトの子でなければならない。
  - Clipping bounds - スクロールコンテンツのマスキングが有効な場合、クリッピングバウンズ要素は、その境界内のスクロール可能なコンテンツのみを確実に表示します。clipping boundsゲームオブジェクトには、disabled box colliderとclipping boxの2つのコンポーネントがあります。

![181.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/ebb08a4e-d4e8-eeaa-9a80-ffcb6350f315.png)

**スクロールオブジェクトへのコンテンツの追加**

スクロールオブジェクトコレクションは、グリッドオブジェクトコレクションと組み合わせることで、サイズと間隔が均一な整列した要素のグリッドにコンテンツをレイアウトすることができます。

- スクロールコンテナの子として、空のゲームオブジェクトを作成します。
- ゲームオブジェクトに、グリッドオブジェクトコレクションコンポーネントを追加します。
- 垂直方向の1列スクロールの場合、インスペクタタブでグリッドオブジェクトコレクションを以下のように設定します。
  - Num columns: 1 
  - Layout: 列→行
  - Anchor：左上
- コンテンツオブジェクトの寸法に合わせて、セルの幅と高さを変更します。
- コンテンツ・オブジェクトをグリッド・オブジェクトの子として追加する。
- update collectionを押します。

![165.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f7142078-50b4-f149-6b55-922aa8220a72.png)

> 重要
> 
> スクロールするコンテンツオブジェクトの素材には、MRTK標準シェーダを使用して、表示領域のクリッピング効果が正しく機能するようにしてください。



> 注意
> 
> スクロールコンテンツマスキングが有効な場合、スクロールオブジェクトコレクションは、レンダラーが接続されているすべてのコンテンツオブジェクトにマテリアルインスタンスコンポーネントを追加します。このコンポーネントは、インスタンス化されたマテリアルの寿命を管理し、メモリのパフォーマンスを向上させるために使用されます。


**スクロールの表示領域の設定**

- オブジェクトの1列を垂直方向にスクロールするには、インスペクタタブで、スクロールオブジェクトコレクションを以下のように設定します。
  - Cells per tier(階層ごとのセル数)：1
  - 表示する列の数に応じて、1ページあたりの階層数を選択
- ページセルの幅、高さ、奥行きをコンテンツオブジェクトの寸法に合わせて変更する。
  
スクロール可能な領域の外側にあるコンテンツオブジェクトは無効化され、スクロールワイヤーフレームと交差するオブジェクトはクリッピングプリミティブによって部分的にマスクされていることに注意してください。

![119.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/520996ab-582c-a8d2-6107-f3d6f20529ee.png)

**エディタでのスクロールオブジェクトコレクションのテスト**

- 再生ボタンを押し、スペースバーを押し続けると、入力シミュレーションの手が表示されます。
- スクロールコライダーまたはスクロールするインタラクティブなコンテンツがフォーカスされるまで手を動かし、左マウスでクリックして上下にドラッグすることでスクロールの動きをトリガーします。
 
**コードからのスクロールオブジェクトの制御**

MRTK スクロールオブジェクトコレクションでは、ページネーションプロパティの設定に従ってスクロールコンテナの位置をスナップして移動できるいくつかのパブリックメソッドを公開しています。

MRTK/Examples/Demos/ScrollingObjectCollection/Scriptsフォルダの下に、スクロール・オブジェクト・コレクションのページネーション・インタフェースにアクセスする方法の例が用意されているので、それを使用することができます。スクロール可能なページネーションのサンプル スクリプトは、シーン内の既存のスクロール オブジェクト コレクションにリンクできます。このスクリプトは、Unityイベントを公開するシーンコンポーネント（MRTKボタンなど）から参照することができます。

```c#
public class ScrollablePagination : MonoBehaviour
{
    [SerializeField]
    private ScrollingObjectCollection scrollView;

    public void ScrollByTier(int amount)
    {
        scrollView.MoveByTiers(amount);
    }       
}
```

**スクロール・オブジェクト・コレクション・プロパティ**

---

|一般||	
|:--|:--|
|Scroll direction| コンテンツがスクロールする方向|


|ページネーション|説明|
|:--|:--|
|Cells per tier| アップダウンスクロールビューでの行のセル数、またはレフトライトスクロールビューでの列のセル数。|
|Tiers per page| スクロール領域に表示される段の数。|
|Page cell| ページネーションセルの寸法|

|詳細設定| 説明|
|:--|:--|
|Mask edit mode| クリッピングボックスのマスキング境界を定義するための編集モード。ページネーションの値を自動的に使用するには「Auto」を選択します。手動」を選択すると、クリッピングボックスオブジェクトを直接操作することができます。|
|Collider edit mode |スクロールインタラクションのコリダー境界を定義するための編集モード。ページネーションの値を自動的に使用するには「Auto」を選択します。手動」を選択すると、コライダを直接操作することができます。|
|Can scroll | 近接／遠距離インタラクションでのスクロールを有効／無効にします。|
|Use on pre render | scrollingObjectCollection が Camera OnPreRender イベントを使用してコンテンツの可視性を管理するかどうかを設定します。|
|Pagination curve | ページネーションのアニメーションカーブ。|
|Animation length | ページネーションカーブが評価されるまでの時間（秒単位）。|
|Hand delta scroll threshold| スクロールドラッグが発生するまでに現在のポインターがスクロール方向に沿って移動できる距離をメートル単位で指定します。|
|Front touch distance| スクロールビューの前面でタッチ操作が開始されたかどうかを確認するために使用されるローカルxy平面を配置する距離をメートル単位で指定します。|
|Release threshold| スクロールの境界から、タッチ操作が行われた状態から解除された状態に移行するために必要な引き出し量をメートル単位で指定します。|

|速度 |説明|
|:--|:--|
|Type of velocity| スクローラーに必要な速度低下のタイプです。|
|Velocity multiplier| スクロールに適用される（追加の）ベロシティの量。|
|Velocity dampen |ベロシティに適用されるフォールオフの量。|
|Bounce multiplier| falloff per frame または falloff per item を使用する際に、リストのオーバースクロールにバウンスを追加するための乗数。|

|デバッグオプション| 説明|
|:--|:--|
|Mask enabled| スクロールコンテンツの表示モード。デフォルトでは、スクロール表示領域外のすべてのオブジェクトがマスクされます。|
|Show threshold planes （しきい値平面の表示） |true の場合、エディタはスクロール境界の周りにタッチリリースのしきい値平面をレンダリングします。|
|Debug pagination| ランタイム中にスクロールのページネーションをデバッグするには、このセクションを使用します。|


|イベント| 説明|
|:--|:--|
|On click| スクロール バックグラウンド コライダーまたはそのインタラクティブ コンテンツがクリックされるとイベントが発生します。|
|On touch started |スクロールバックコレクタまたはそのインタラクティブコンテ ンツが near interaction touch を受信したときに発生するイベント。|
|On touch ended |イベントは、アクティブなタッチインタラクションが、near interaction pointer が release threshold plane のいずれかを越えることによって終了したときに発生します。|
|On momentum started |スクロールコンテナがインタラクション、velocity fallofff または pagination によって移動を開始したときに発生するイベント。|
|On momentum ended |スクロールコンテナがインタラクション、velocity fallofffまたはpaginationによって移動を停止したときに発生するイベント。|

**スクロールのサンプルシーン**

ScrollingObjectCollection.unityのサンプルシーンは、3つのスクロール可能なサンプルで構成されており、それぞれが異なるベロシティファルオフの設定を持っています。このサンプルシーンには、階層ではデフォルトで無効になっているサーフェス配置の動作を示すための壁が含まれています。このサンプルシーンは、MRTK/Examples/Demos/ScrollingObjectCollection/Scenesフォルダの下にあります。

![49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/91520057-8994-77d7-4189-aa472906e3a7.png)

**スクロールサンプルプレハブ**

便利なように、2つのスクロールオブジェクトコレクションのプレハブを使用することができます。サンプルプレファブはMRTK/Examples/Demos/ScrollingObjectCollection/Prefabsフォルダの下にあります。

![243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/54f669ef-a607-e660-39fc-90050a5671e2.png)

# Dock

![91.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/fa8a46ad-dd81-575e-b111-c59a8f1a8c59.png)


このコントロールは、パレットや棚、ナビゲーションバーを作成するために、あらかじめ設定された位置にオブジェクトを出し入れすることができます。

**特徴**

- 任意の数のドックポジションとレイアウトをサポート (GridObjectCollectionとの相性が良い)
- ドックされたオブジェクトは自動的に移動し、新しいオブジェクトのためのスペースを確保
- オブジェクトはドッキングされたスペースに合わせて拡大縮小され、ドラッグアウトすると元の位置に戻ります。

**Dockを使い始める**

- Dockコンポーネントを持つGameObjectを作成し、そこにいくつかのchildren GameObjectを追加する。
- それぞれの子にDockPositionコンポーネントを追加する。
- シーン内の任意の数のオブジェクトにDockableコンポーネントを追加して、ドッキングできるようにします。これらのオブジェクトには、ObjectManipulatorコンポーネントとColliderが必要です。
- オプション：DockにGridObjectCollectionを使用して、DockPositionを自動的にレイアウトします。

**前提条件**

- すべてのドッキング可能なオブジェクトは、ObjectManipulatorまたはManipulationHandlerを持つColliderを持っている必要があります。
- シーンがロードされたときにオブジェクトをドッキングさせたい場合は、任意のDockPositionのdocked object propertyに割り当ててください。

**動作原理**

Dockableコンポーネントは、操作イベントを基にして、ドラッグされたオブジェクトを特定の位置にドッキングしたり、ドッキング解除したりすることができます。配置は、トリガーされたDockPositionがドラッグされたオブジェクトに最も近く重なっているかどうかで決定されるため、トリガーが有効になるには両方のオブジェクトにColliderが必要です。




# 視線追跡: ターゲット選択

![168.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/04b76c6c-62e3-2d40-41c7-0174ac2e8571.png)

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/input/eye-tracking/eye-tracking-target-selection?view=mrtkunity-2021-01

# 視線追跡: ナビゲーション

![226.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/58a329cb-e64d-36af-e6af-1d4dd599f508.png)


https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/input/eye-tracking/eye-tracking-navigation?view=mrtkunity-2021-01

# 視線追跡: ヒート マップ

![125.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/f82e3c18-b76d-73cb-e40b-75d4aecadc65.png)

https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/example-scenes/eye-tracking-examples-overview?view=mrtkunity-2021-01#visualization-of-visual-attention

# シーンのSample

![207.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/61f4ab80-2561-c2e1-c644-c671eb6fa054.png)


https://docs.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/features/example-scenes/hand-interaction-examples?view=mrtkunity-2021-01

# MRTK Examples Hub

![208.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/d72dae19-6082-7364-72a2-db9a4a826859.png)

https://www.microsoft.com/p/mrtk-examples-hub/9mv8c39l2sj4

# MRTK を使用して作成されたサンプルアプリ

![231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/9bbc7bc2-6b93-cc98-6974-9801aaab0a84.png)

[Periodic Table of the Elements](https://github.com/Microsoft/MRDL_Unity_PeriodicTable)

![50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/8cdc1b67-3a99-7557-e5cd-da2b31e5a51d.png)

[Galaxy Explorer](https://github.com/Microsoft/GalaxyExplorer)

![164.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151589/de680c7e-508c-335b-b3fb-239f827b7163.png)

[Surfaces](https://github.com/microsoft/MRDL_Unity_Surfaces)

以上。