本日は MRTK と UniRx の小ネタ枠です。
MRTKの手の検出イベントをUniRxのオブザーバで処理する方法を記事にします。
FromEvent
FromEvent はイベントから Observable を作成する UniRx のファクトリメソッドです。
以下のように Action クラスから Observable を作成することができます。
Action OnEvent; IObservable OnEventObservable = Observable.FromEvent( action => OnEvent += action, action => OnEvent -= action );
引数のあるイベントの場合は以下のように作成します。
Action<int> OnEvent; IObservable<int> OnEventObservable = Observable.FromEvent<int>( action => OnEvent += action, action => OnEvent -= action );
IMixedRealitySourceStateHandlerとIMixedRealityHandJointHandler
IMixedRealitySourceStateHandler と IMixedRealityHandJointHandler は手の検出時にイベントを発生させるハンドラです。
OnSourceDetected と OnSourceLost で手の検出とロストをイベントとして取得できます。
OnHandJointsUpdated で詳細な手の関節(ハンドジョイント)情報を取得できます。
docs.microsoft.com
サンプルコード
以下のようなサンプルコードを作成しました。
3つの手の検出イベントそれぞれのオブザーバを作成し、情報をログに出力しています。
OnHandJointsUpdated のみ常に Handedness.None イベントが発生するため、Where オペレータで除外しています。
・TestFromEvent.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using Microsoft.MixedReality.Toolkit; using Microsoft.MixedReality.Toolkit.Input; using Microsoft.MixedReality.Toolkit.Utilities; using UniRx; namespace HMProject.Test { public class TestFromEvent : MonoBehaviour, IMixedRealitySourceStateHandler, IMixedRealityHandJointHandler { // 手の検出時に呼び出すアクション private Action<SourceStateEventData> OnSourceDetectedAction; // 手のロスト時に呼び出すアクション private Action<SourceStateEventData> OnSourceLostAction; // 手の更新時に呼び出すアクション private Action<InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>>> OnHandJointsUpdatedAction; /// <summary> /// 手の検出時に発生するイベント(IMixedRealitySourceStateHandler) /// </summary> /// <param name="eventData"></param> public void OnSourceDetected(SourceStateEventData eventData) { // アクション呼び出し OnSourceDetectedAction(eventData); } /// <summary> /// 手のロスト時に発生するイベント(IMixedRealitySourceStateHandler) /// </summary> /// <param name="eventData"></param> public void OnSourceLost(SourceStateEventData eventData) { // アクション呼び出し OnSourceLostAction(eventData); } /// <summary> /// 手の更新時に発生するイベント(IMixedRealityHandJointHandler) /// </summary> /// <param name="eventData"></param> public void OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData) { // アクション呼び出し OnHandJointsUpdatedAction(eventData); } /// <summary> /// 起動処理 /// </summary> void Start() { // 手の検出時オブザーバを作成する IDisposable OnSourceDetectedObserver = Observable .FromEvent<SourceStateEventData>( action => OnSourceDetectedAction += action, action => OnSourceDetectedAction -= action ) .Subscribe(eventData => { Debug.Log("!!! OnSourceDetected !!! - SourceId : " + eventData.SourceId.ToString()); }) .AddTo(this); // 手のロスト時オブザーバを作成する IDisposable OnSourceLostObserver = Observable .FromEvent<SourceStateEventData>( action => OnSourceLostAction += action, action => OnSourceLostAction -= action ) .Subscribe(eventData => { Debug.Log("!!! OnSourceLost !!! - SourceId : " + eventData.SourceId.ToString()); }) .AddTo(this); // 手の更新時オブザーバを作成する IDisposable OnHandJointsUpdatedObserver = Observable .FromEvent<InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>>>( action => OnHandJointsUpdatedAction += action, action => OnHandJointsUpdatedAction -= action ) .Where(eventData => eventData.Handedness != Handedness.None) // Noneイベントは処理しない .Subscribe(eventData => { Debug.Log("!!! OnHandJointsUpdated !!! " + "- SourceId : " + eventData.SourceId.ToString() + ", Handedness : " + eventData.Handedness.ToString()); }) .AddTo(this); } /// <summary> /// 有効時処理 /// </summary> private void OnEnable() { // ハンドラ登録 CoreServices.InputSystem?.RegisterHandler<IMixedRealityHandJointHandler>(this); CoreServices.InputSystem?.RegisterHandler<IMixedRealitySourceStateHandler>(this); } /// <summary> /// 無効時処理 /// </summary> private void OnDisable() { // ハンドラ解除 CoreServices.InputSystem?.UnregisterHandler<IMixedRealityHandJointHandler>(this); CoreServices.InputSystem?.UnregisterHandler<IMixedRealitySourceStateHandler>(this); } } }
スクリプトを適当なオブジェクトに追加します。
動作確認
シーンを再生して動作を確認します。
ログを確認すると、手の検出イベントをオブザーバが受け取っていることが分かります。
これで MRTK で発生するイベントを UniRx の仕組みを使ってフィルタリングすることができます。