MRが楽しい

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

HoloLens2でホロモンアプリを作る その30(ホロモンの視野から障害物に遮られたオブジェクトを除外する)

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

今回はホロモンの視野から障害物に遮られたオブジェクトを除外するメモです。

障害物の有無を判定する

今回、ホロモンの視野における障害物を判定するため、以下のようなコードを作成しました。
ホロモンの頭の位置と、検出オブジェクトの位置を算出し、その直線上に別のオブジェクトが存在するかチェックします。

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

// レイキャストの結果
RaycastHit[] raycastHits = new RaycastHit[3];

// レイキャストでその方向の衝突オブジェクトを検知する
int hitCount = Physics.RaycastNonAlloc(p_VisionRoot.position, betweenDirection, raycastHits, betweenDistance);

if (hitCount > 1)
{
    // ヒット数が 1 以上なら障害物(対象以外)があるとみなして無視する
    return;
}

ホロモンの視野から障害物に遮られたオブジェクトを除外する

前回作成したスクリプトにこの障害物検知の機能を追加します。
bluebirdofoz.hatenablog.com

サンプルスクリプトとして以下のスクリプトを作成しました。
コライダーの範囲で検出されたオブジェクトが視野角に収まるか、視界原点との間に障害物がないかを判定します。
・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;
            }

            // レイキャストの結果
            RaycastHit[] raycastHits = new RaycastHit[3];

            // レイキャストでその方向の衝突オブジェクトを検知する
            int hitCount = Physics.RaycastNonAlloc(p_VisionRoot.position, betweenDirection, raycastHits, betweenDistance);

            if (hitCount > 1)
            {
                // ヒット数が 1 以上なら障害物(対象以外)があるとみなして無視する
                Debug.Log("OnTriggerStay : " + collider.name + " is invisible to obstacles.");
                return;
            }

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

f:id:bluebirdofoz:20210412233427j:plain

前回と同様に、このスクリプトをオブジェクトを検出する Collider を設定したオブジェクトに設定します。
f:id:bluebirdofoz:20210412233440j:plain

シーンを再生して動作を確認します。
ホロモンの正面にいるときは障害物がないため、見えていると判定されます。
f:id:bluebirdofoz:20210412233453j:plain

そのまま下がり、空間認識レイヤーの裏側に回り込みました。
すると間に障害物となる壁があるため、見えていないと判定されました。
f:id:bluebirdofoz:20210412233505j:plain