MRが楽しい

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

HoloLens2でホロモンアプリを作る その71(ホロモンが指さしたところを見る)

本日はアプリ作成枠です。
HoloLens2でホロモンアプリを作る進捗を書き留めていきます。
f:id:bluebirdofoz:20211114215537j:plain

今回はホロモンが指さしたところを見るメモです。

前提条件

以下の記事で検証したハンドレイのポインター座標を検出する方法を利用します。
bluebirdofoz.hatenablog.com

また、今回は手の形を「ピストル」の形にしたときのみホロモンが指さしたところを見るようにします。
手の形を検出する方法は以下の記事で紹介しています。
bluebirdofoz.hatenablog.com

実装コード

前提条件の記事で作成したスクリプトを改修し、以下のスクリプトを作成しました。
手が「ピストル」の形をしているときのみ、ポインター座標のオブジェクトを有効化します。
・HandRayTracker.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Microsoft.MixedReality.Toolkit;
using Microsoft.MixedReality.Toolkit.Utilities;
using Microsoft.MixedReality.Toolkit.Input;

using HoloMonApp.DataFormatSpace;

namespace HoloMonApp.Player
{
    public class HandRayTracker : MonoBehaviour, IMixedRealityHandJointHandler, IMixedRealitySourceStateHandler
    {
        [SerializeField, Tooltip("参照するハンドタイプの指定")]
        private Handedness p_HandednessType;

        [SerializeField, Tooltip("参照するハンド状態")]
        private ObjectFeatures p_HandFeatureRef;

        /// <summary>
        /// ポインターオブジェクトの参照
        /// </summary>
        [SerializeField, Tooltip("ポインターオブジェクトの参照")]
        private GameObject p_Pointer;

        /// <summary>
        /// 現在参照中のハンドレイ
        /// </summary>
        private ShellHandRayPointer p_ShellHandRayPointer;


        /// <summary>
        /// 手の検出時に発生するイベント(IMixedRealitySourceStateHandler)
        /// </summary>
        /// <param name="eventData"></param>
        public void OnSourceDetected(SourceStateEventData eventData)
        {
            // 既に対象を検出済みの場合は処理しない
            if (p_ShellHandRayPointer != null) return;

            // 現在監視対象のポインターが存在するか
            ShellHandRayPointer handRayPointer = DetectionTargetHandRay();
            if (handRayPointer == null) return;

            // 対象が見つかった場合参照を取得しておく
            p_ShellHandRayPointer = handRayPointer;
        }

        /// <summary>
        /// 手のロスト時に発生するイベント(IMixedRealitySourceStateHandler)
        /// </summary>
        /// <param name="eventData"></param>
        public void OnSourceLost(SourceStateEventData eventData)
        {
            // 既に対象を削除済みの場合は処理しない
            if (p_ShellHandRayPointer == null) return;

            // 現在監視対象のポインターが存在するか
            ShellHandRayPointer handRayPointer = DetectionTargetHandRay();
            if (handRayPointer != null) return;

            // 対象が見つからなくなっている場合ロスト処理を行う
            p_ShellHandRayPointer = null;
        }

        /// <summary>
        /// 手の更新時に発生するイベント(IMixedRealityHandJointHandler)
        /// </summary>
        /// <param name="eventData"></param>
        public void OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData)

        {
            // 監視対象のポインターが取得済みか
            if (p_ShellHandRayPointer == null) return;

            // ハンドオブジェクトの状態を取得する
            ObjectStatusHand handStatus = ObjectStatusHand.Nothing;
            switch (p_HandednessType)
            {
                case Handedness.Right:
                    handStatus = p_HandFeatureRef?.Features?.ObjectUnderstandFriendRightHandData?.HandStatus ?? ObjectStatusHand.Nothing;
                    break;
                case Handedness.Left:
                    handStatus = p_HandFeatureRef?.Features?.ObjectUnderstandFriendLeftHandData?.HandStatus ?? ObjectStatusHand.Nothing;
                    break;
                default:
                    break;
            }

            // 手の形がピストルでなければポインター座標は有効化しない
            if (handStatus != ObjectStatusHand.Hand_Pistol)
            {
                // ポインターオブジェクトを無効化する
                p_Pointer.SetActive(false);

                return;
            }

            // ポインターオブジェクトを有効化する
            p_Pointer.SetActive(true);

            // ポインターのレイキャスト座標にポインターオブジェクトを移動する
            Vector3 handRayPosition = p_ShellHandRayPointer?.BaseCursor?.Position ?? new Vector3();
            p_Pointer.transform.position = handRayPosition;
        }

        /// <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);
        }

        // Start is called before the first frame update
        void Start()
        {
            // デフォルトはポインターOFF
            p_Pointer.SetActive(false);
        }

        // Update is called once per frame
        void Update()
        {
        }

        /// <summary>
        /// MRTKのInputSystemから監視対象のハンドレイポインターを取得する
        /// </summary>
        /// <returns></returns>
        private ShellHandRayPointer DetectionTargetHandRay()
        {
            ShellHandRayPointer handRayPointer = null;

            // 現在のInputSystemに対象が存在するかチェックする
            foreach (IMixedRealityInputSource inputSource in CoreServices.InputSystem.DetectedInputSources)
            {
                foreach (IMixedRealityPointer pointer in inputSource.Pointers)
                {
                    // ハンドレイでなければ対象外
                    if (pointer.GetType() != typeof(ShellHandRayPointer)) continue;
                    // 指定のハンドタイプでなければ対象外
                    if (((ShellHandRayPointer)pointer).Handedness != p_HandednessType) continue;

                    handRayPointer = (ShellHandRayPointer)pointer;
                }
            }

            return handRayPointer;
        }
    }
}

f:id:bluebirdofoz:20211114215615j:plain

シーンへの配置

適当なオブジェクトに作成したスクリプトを追加します。
手の状態を取得するため、ハンドオブジェクトへの参照とポインター座標を示すオブジェクトへの参照を設定しておきます。
f:id:bluebirdofoz:20211114215627j:plain

ポインター座標を示すオブジェクトにはホロモンがポインターとして認識できるよう識別用のスクリプトを設定しています。
f:id:bluebirdofoz:20211114215637j:plain

動作確認

シーンを再生して動作を確認します。
f:id:bluebirdofoz:20211114215646j:plain

手を閉じた形にしているときはポインター位置は無効化されており、ホロモンは手のオブジェクトの方を見ています。
f:id:bluebirdofoz:20211114215656j:plain

手をピストルの形にするとポインター位置が有効化され、ホロモンは指をさした場所を見てくれました。
f:id:bluebirdofoz:20211114215705j:plain