MRが楽しい

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

HoloLens2でホロモンアプリを作る その29(ホロモンの視野内のオブジェクトを検出する)

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

今回はホロモンの視野内のオブジェクトを検出するメモです。

視野角を判定する

今回、ホロモンの視野角を判定するため、以下のようなコードを作成しました。
ホロモンの頭の方向と、検出オブジェクトの方向の角度を算出し、視野角に収まる範囲にオブジェクトが存在するか判定します。

// 視界原点とオブジェクト間のベクトルを算出し、距離と方向ベクトルを取得する
Vector3 betweenVector = collider.transform.position - p_VisionRoot.position;
float betweenDistance = betweenVector.magnitude;
Vector3 betweenDirection = betweenVector.normalized;

// 視界原点の方向ベクトルを取得する
Vector3 headDirection = p_VisionRoot.rotation * Vector3.forward;

// 2つの方向ベクトルの角度差(0°~360°)を取得する
float diffAngle = Vector3.Angle(headDirection, betweenDirection);

if (diffAngle > p_ViewingAngle)
{
    // 視野角外の場合は無視する
    Debug.Log("OnTriggerStay : " + collider.name + " is Out of ViewingAngle.");
    return;
}

ホロモンの視野内のオブジェクトを検出する

サンプルスクリプトとして以下のスクリプトを作成しました。
コライダーの範囲で検出されたオブジェクトが視野角に収まるか否かを判定します。
・VisionTest.cs

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

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

namespace HMProject.Test
{
    [RequireComponent(typeof(Collider))]
    public class VisionTest : MonoBehaviour
    {
        [SerializeField, Tooltip("空間認識レイヤー番号")]
        int p_SpatialAwarenessLayer;

        [SerializeField, Tooltip("視界原点トランスフォーム")]
        private Transform p_VisionRoot;

        [SerializeField, Tooltip("視野角")]
        private float p_ViewingAngle = 60;


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

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


        private void OnTriggerStay(Collider collider)
        {
            // オブジェクトのレイヤー番号を取得する
            int layernumber = collider.gameObject.layer;

            if (layernumber == p_SpatialAwarenessLayer)
            {
                // 空間認識レイヤーの場合は無視する
                Debug.Log("OnTriggerStay : " + collider.name + " is Spatial Awareness Layer.");
                return;
            }

            // 視界原点とオブジェクト間のベクトルを算出し、距離と方向ベクトルを取得する
            Vector3 betweenVector = collider.transform.position - p_VisionRoot.position;
            float betweenDistance = betweenVector.magnitude;
            Vector3 betweenDirection = betweenVector.normalized;

            // 視界原点の方向ベクトルを取得する
            Vector3 headDirection = p_VisionRoot.rotation * Vector3.forward;

            // 2つの方向ベクトルの角度差(0°~360°)を取得する
            float diffAngle = Vector3.Angle(headDirection, betweenDirection);
            Debug.Log("OnTriggerStay : " + collider.name + ", Angle : " + diffAngle.ToString());

            if (diffAngle > p_ViewingAngle)
            {
                // 視野角外の場合は無視する
                Debug.Log("OnTriggerStay : " + collider.name + " is Out of ViewingAngle.");
                return;
            }

            // 視野角に収まる場合は見えていると判定する
            Debug.Log("OnTriggerStay : " + collider.name + " can be seen.");
        }
    }
}

f:id:bluebirdofoz:20210411223809j:plain

このスクリプトをオブジェクトを検出する Collider を設定したオブジェクトに追加します。
f:id:bluebirdofoz:20210411223824j:plain

更にホロモンからの視野を判定するため、頭部トランスフォームを指定して準備は完了です。
f:id:bluebirdofoz:20210411223836j:plain

シーンを再生して動作を確認します。
ホロモンの正面にいるときは視野角に収まるため、見えていると判定されます。
f:id:bluebirdofoz:20210411223847j:plain

そのままホロモンの側面に回り込みます。
すると視野角から外れ、見えていないと判定されました。
f:id:bluebirdofoz:20210411223859j:plain