MRが楽しい

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

MRTKの空間認識メッシュを使ってオブジェクトの地面からの高さを計算する

本日は MRTK の小ネタ枠です。
MRTKの空間認識メッシュを使ってオブジェクトの地面からの高さを計算する方法を記事にします。

MRTKの空間認識

MRTK の空間認識システムではアプリケーション内で現実世界のジオメトリを表すメッシュのコレクションが提供されます
docs.microsoft.com

MRTK の基本設定を行ったプロジェクトでは以下の通り、空間認識メッシュのレイヤー番号を取得できます。

// 空間認識のオブザーバを取得する
IMixedRealitySpatialAwarenessMeshObserver SpatialAwarenessMeshObserver =
    CoreServices.GetSpatialAwarenessSystemDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();

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

MRTK のインポートとサンプルシーンの作成MRTKの基本設定

MRTK のインポートと HoloLens 向けプロジェクトの基本設定の手順は以下の記事を参照してください。
bluebirdofoz.hatenablog.com

また MRTK の MeshObservers を利用すると Unity エディター上で仮想メッシュを表示して動作確認を行うことができます。
bluebirdofoz.hatenablog.com

今回はこれらの設定を既に行っているホロモンアプリのプロジェクト上で試します。
f:id:bluebirdofoz:20211223233032j:plain

サンプルコード

アタッチされたオブジェクトから真下の空間認識レイヤーに Raycast を飛ばして高さを求めるサンプルコードを作成しました。
・HeadHeightChecker.cs

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

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

namespace HoloMonApp.Player
{
    public class HeadHeightChecker : MonoBehaviour
    {
        [SerializeField, Tooltip("高さの上限値(m)")]
        private float p_HeightMax = 2.0f;

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

        [SerializeField, Tooltip("現在の高さ(m)")]
        private float p_CurrentHeight;

        /// <summary>
        /// 現在の高さ(m)
        /// </summary>
        public float CurrentHeight => p_CurrentHeight;


        // Start is called before the first frame update
        void Start()
        {
            // 空間認識のオブザーバを取得する
            IMixedRealitySpatialAwarenessMeshObserver SpatialAwarenessMeshObserver =
                CoreServices.GetSpatialAwarenessSystemDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();

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

        // Update is called once per frame
        void Update()
        {
            // レイキャストをプレイヤーの位置から真下に落とす
            Vector3 playerPosition = this.gameObject.transform.position;
            Ray ray = new Ray(playerPosition, -Vector3.up);

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

            // レイキャストのヒット情報を取得する
            if (Physics.Raycast(ray, out RaycastHit hitInfo, Mathf.Infinity, layerMask))
            {
                // ヒット位置(高さ)が上限値を超えていなければ高さとして代入する
                p_CurrentHeight = (hitInfo.distance < p_HeightMax) ? hitInfo.distance : p_HeightMax;
            }
        }
    }
}

レイキャストのレイヤーマスクを設定して空間認識レイヤーにのみ、レイキャストがヒットするようにしています。
docs.unity3d.com

今回はこのスクリプトをプレイヤーの頭部追従オブジェくトに設定して、プレイヤーの頭の高さを計測してみます。
f:id:bluebirdofoz:20211223233051j:plain

動作確認

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

CurrentHeight の変数を参照すると、空間認識メッシュからの現在の高さが取得できます。
f:id:bluebirdofoz:20211223233110j:plain