MRが楽しい

MRやVRについて学習したことを書き残す

MetaHorizonの開発ドキュメントを読む その35(Interaction Broadcaster)

本日はMetaQuestの学習枠です。
MetaHorizonの開発ドキュメントを読みながら実際に開発を行ってみました。

MetaHorizonの開発ドキュメント

MetaHorizonの開発ドキュメントを実際に手を動かしながら実行時のキャプチャをしていきます。
developers.meta.com

本記事は以下の「Interaction Broadcaster」の記事を試します。
developers.meta.com

Interaction Broadcaster

Interaction Broadcaster(インタラクションブロードキャスター)は3DやUIソースからの変化を含む、全てのインタラクション状態の変化を監視するシーンレベルのシングルトンです。
ScriptableObjectのInteractionEventChannelと静的なC#イベントを使用して、これらの変化を再ブロードキャストします。
これにより分析、チュートリアル、グローバルUI、フィードバックマネージャなどのシステムのためのデータソースを一元化できます。

概要

ほとんどのインタラクションは統一されたポインターライフサイクルとポインターイベントモデル(識別子、イベントタイプ、ポーズ、データ)に準拠しています。
ブロードキャスターはインタラクターとインタラクタブル全体にわたるこれらの変更を監視し、InteractionEvent構造体に正規化して、以下のイベントを発生させます。

  • InteractionEventChannel.OnEventRaised(インスペクター対応)
  • InteractionBroadcaster.OnEventRaised(C#静的イベント)

このパターンにより、密結合が回避され、シーン全体の動作を容易に監視できます。

仕組み

インタラクションブロードキャスターは自動登録機能を使用して一般的なタイプのインタラクター(手、コントローラー、光線などの入力ソース)とインタラクタブル(ボタン、パネル、掴めるオブジェクトなど)間の接続を自動的に設定します。

インタラクションブロードキャスターはインタラクションイベントをモジュール化され、疎結合な方法で処理できるイベントフローを使用します。
このライフサイクルは以下のフローで構成されます。

  1. ボタンや掴めるアイテムなどのインタラクティブなオブジェクトはホバー、掴む、突くなどのインタラクションイベントを検出します。
  2. ハンドラーはインタラクションイベントを処理し、ホバー、選択、移動などのイベントタイプを判別します。
  3. ブロードキャスターはイベントをInteractionEventChannelに送信し、他のシステムで利用できるようにします。
  4. 設定によってはブロードキャスターはイベントをUnityEvent、C#デリゲートイベントまたはカスタムイベントシステムを使用してチャネルに送信することもできます。
  5. このイベントを購読しているすべてのスクリプト、コンポーネントおよびシステムはイベントを受信し、応答することができます。

セットアップ

インタラクションブロードキャスターをシーンに追加する方法は2つあります。

FeedbackManagerプレハブを使用する (推奨)

FeedbackManagerプレハブにはInteractionBroadcasterコンポーネントが含まれています。
以下のプレハブをシーンの階層のルートにドラッグします。

Packages/Meta XR Interaction SDK/Runtime/Prefabs/Feedback/FeedbackManager.prefab

このプレハブには、InteractionBroadcaster と InteractionEventChannel が既に設定されています。

スタンドアロンブロードキャスター

Feedback Managerを使用せずにイベントブロードキャストのみが必要な場合は以下の手順に従ってください。
Hierarchyで空いている領域を右クリックし、[Create Empty] を選択し、作成したオブジェクトの名前を「InteractionBroadcaster」とします。
Inspectorで[add Component]をクリックし、InteractionBroadcasterを追加します。

イベントを購読する

ユースケースに合った以下のオプションを選択してください。

  • デザイナー配線用のScriptableObjectチャネル(UnityEvents、VFXなどに接続)。
  • オーバーヘッドを抑えたい場合は静的C#イベントを使用してください。

購読するイベントをフィルタリングするには、以下のオプションのいずれかを使用してください。

  • インタラクションタイプ(ホバー/ホバー解除/選択/選択解除/移動/キャンセル、およびUIタイプ)
  • ソースGameObject(単一オブジェクトを監視)
  • インタラクター(識別子またはInteractorViewを使用)

APIリファレンス

インタラクションブロードキャスターはイベント監視のために以下のAPIを提供します。

InteractionBroadcaster

static InteractionBroadcaster Instance { get; }

InteractionBroadcaster のシングルトンインスタンス

static event Action OnEventRaised

何らかのインタラクションが発生したときに発生する静的 C# イベント

static void RegisterCustomInteractionType()

自動イベントブロードキャスト用にカスタムインタラクターとインタラクタブルのペアを登録します

void RegisterInteractionType()

カスタムインタラクションタイプを登録するためのインスタンスメソッド

InteractionEventChannel

event Action OnEventRaised

インスペクター配線用の ScriptableObject ベースのイベント

void Raise(in InteractionEvent evt)

インタラクションイベントを手動で発生させます

InteractionEvent

InteractionType _type

インタラクションの種類 (ホバー、選択、移動など)

IInteractorView InteractorView

イベントをトリガーしたインタラクター

GameObject _source

インタラクションされたソース GameObject

int _pointerId

ポインタベースのインタラクションの一意の識別子

ベストプラクティス

  • メモリリークを防ぎドメインの再読み込みに対応するため、OnDisableメソッド内で必ず購読を解除してください。
  • デザイナーで設定可能なイベントルーティングが必要で多少のオーバーヘッドを許容できる場合はInspectorの配線にScriptableObjectチャネルを使用してください。
  • パフォーマンスが重要なコードパスには静的イベントを使用してください。
  • _sourceまたはInteractorViewにアクセスする前に、必ずnullチェックを行ってください。
  • インタラクションを監視する必要があるシステム (チュートリアル、分析、実績など) では個々のインタラクティブオブジェクトにリスナーをアタッチするのではなく、中央集権型のブロードキャスターを購読し、イベントをフィルタリングしてください。

トラブルシューティング

問題:インタラクションをトリガーした後、ブロードキャスターがイベントを発信しない

シーンでInteractionBroadcasterコンポーネントがアクティブになっていることを確認してください。
インスペクターでInteractionBroadcasterコンポーネントの「Auto Register」オプションが有効になっていることを確認してください。

カスタムインタラクタータイプを使用している場合はブロードキャスターの起動後にRegisterCustomInteractionType()が呼び出されていることを確認してください。
イベントが発火していることを確認するために簡単なデバッグリスナーを追加してください。

InteractionBroadcaster.OnEventRaised += (evt) => Debug.Log($"Event: {evt._type}");

問題:カスタムインタラクター型がイベントをブロードキャストしない

カスタム型を正しく登録してください。
スクリプトのStart()メソッドで、ブロードキャストが初期化された後にRegisterCustomInteractionType()を呼び出してください。

カスタム型が必要なISDKインターフェイス (IInteractor、IInteractable) を実装していることを確認してください。
カスタム型がISDKレジストリに正しく統合されていることを確認してください。

問題:UIポインターイベントが受信されない

UI設定を確認してください。HierarchyでCanvasを選択します。
インスペクターでPointableCanvasコンポーネントとPointableCanvasUnityEventWrapperコンポーネントがアタッチされ、キャンバスを参照していることを確認してください。

コンポーネントが存在しない場合は「Add Component」をクリックし、PointableCanvasModuleとPointableCanvasUnityEventWrapperを検索してください。