MRが楽しい

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

HoloLens2でホロモンアプリを作る その39(NavMeshAgentの追跡先を足元の空間認識レイヤー上の位置に設定する)

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

今回は NavMeshAgent の追跡先を足元の空間認識レイヤー上の位置に設定するメモです。

NavMeshAgent の追跡先を足元の空間認識レイヤー上の位置に設定する

前回記事では追跡ターゲットとの距離を測り、追跡成功と失敗を判定するスクリプトを作成しました。
bluebirdofoz.hatenablog.com

しかし、実際に現実空間で人の位置を追跡対象とした場合、HoloLens2 の位置は頭部の位置になります。
このため、NavMesh で追跡を行う空間認識レイヤーからは身長分高い位置に追跡ターゲットが存在します。

距離で追跡成功を正確に判定する場合、追跡対象も空間認識レイヤー上に追跡ターゲットが存在する必要があります。
そこで以下のように真下方向にレイを飛ばし、空間認識レイヤーが存在する場合、その位置をポイントするスクリプトを作成しました。
・FootPositionTracking.cs

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

// CoreSystemへのアクセスのため
using Microsoft.MixedReality.Toolkit;
// 空間認識情報の取得のため
using Microsoft.MixedReality.Toolkit.SpatialAwareness;


namespace HMProject.HoloMonMoveAgent
{
    public class FootPositionTracking : MonoBehaviour
    {
        /// <summary>
        /// 追跡跡オブジェクトのトランスフォーム
        /// </summary>
        [SerializeField, Tooltip("追跡オブジェクトのトランスフォーム")]
        private Transform p_TrackingTransform;

        /// <summary>
        /// 高さのオフセット
        /// </summary>
        [SerializeField, Tooltip("高さのオフセット")]
        private float p_YAxisOffset = 0.1f;

        /// <summary>
        /// 足元までの上限距離
        /// </summary>
        [SerializeField, Tooltip("足元までの上限距離")]
        private float p_HeightMax = 2.0f;

        /// <summary>
        /// 空間認識レイヤー(ヒット判定レイヤー)
        /// </summary>
        [SerializeField, Tooltip("空間認識レイヤー(ヒット判定レイヤー)")]
        int p_SpatialAwarenessLayer;


        /// <summary>
        /// 開始処理
        /// </summary>
        void Start()
        {
            // 空間認識のオブザーバを取得する
            IMixedRealitySpatialAwarenessMeshObserver SpatialAwarenessMeshObserver =
                CoreServices.GetSpatialAwarenessSystemDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();

            // オブザーバからレイヤー番号を取得する
            p_SpatialAwarenessLayer = SpatialAwarenessMeshObserver.MeshPhysicsLayer;

        }

        /// <summary>
        /// 定期処理
        /// </summary>
        void LateUpdate()
        {
            if(p_TrackingTransform == null)
            {
                return;
            }

            // 追跡の正否
            bool isTracking = false;

            // レイキャストを追跡対象の位置から真下に落とす
            Ray ray = new Ray(p_TrackingTransform.position, -Vector3.up);
            RaycastHit hitInfo = new RaycastHit();

            // 空間認識レイヤー用マスク
            int layerMask = 1 << p_SpatialAwarenessLayer;

            // レイキャストのヒット情報を取得する
            if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerMask))
            {
                // ヒット位置が上限距離を超えているかチェックする
                if (hitInfo.distance < p_HeightMax)
                {
                    // 超えていなければヒット位置を足元として自身の位置を移動する
                    this.transform.position = new Vector3(
                        hitInfo.point.x,
                        hitInfo.point.y + p_YAxisOffset,
                        hitInfo.point.z);
                    // 追跡の成功
                    isTracking = true;
                }
            }
            if (isTracking == false)
            {
                // ヒットに失敗した場合は追跡対象の真下かつ上限距離の位置に自身の位置を移動する
                this.transform.position = new Vector3(
                    p_TrackingTransform.position.x,
                    p_TrackingTransform.position.y - p_HeightMax,
                    p_TrackingTransform.position.z);
            }
        }

        public void SetTrackingTransform(Transform a_TargetTransform)
        {
            p_TrackingTransform = a_TargetTransform;
        }

        public void ClearTrackingTransform()
        {
            p_TrackingTransform = null;
        }
    }
}

f:id:bluebirdofoz:20210505183229j:plain

例えば本スクリプトの p_TrackingTransform にカメラのトランスフォームを設定すると、プレイヤーの足元位置にオブジェクトが追従するようになります。
レイキャストのレイヤーマスクの設定方法の詳細は以下を参照ください。
docs.unity3d.com

シーンを再生して動作を確認してみます。
ホロモンに「おいで」と言って、プレイヤーを追跡させます。
f:id:bluebirdofoz:20210505183250j:plain

すると以下の通り、NavMesh の追跡先はプレイヤーの足元位置に設定されるようになり、頭部が高い位置にあっても追跡成功と判定されます。
f:id:bluebirdofoz:20210505183259j:plain

空間認識レイヤーを基に足元の位置を決定しているため、以下のようにホロモンが登れない高い場所に上った場合はちゃんと追跡失敗と判定されます。
f:id:bluebirdofoz:20210505183310j:plain