MRが楽しい

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

MRTKv2.xで空間メッシュと視線の衝突位置を取得する

本日はMRTKv2.xの小ネタ枠です。
MRTKv2.xで空間メッシュと視線の衝突位置を取得する方法を記事にします。

前提条件

本記事の動作確認を実施するため、以下の前回記事の環境を利用します。
bluebirdofoz.hatenablog.com

空間メッシュとの当たり判定を取得する

Physics.Raycast関数を利用して特定レイヤーとレイの衝突位置を取得することができます。
docs.unity3d.com

if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity, layerMask))
{
    Debug.Log("Did Hit");
}

また空間メッシュのレイヤー番号はスクリプトから以下の方法で取得できます。
bluebirdofoz.hatenablog.com

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

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

サンプルスクリプト

現在のカメラ視点からレイを飛ばし、空間メッシュに衝突した位置に移動するサンプルスクリプトを作成しました。
・SpatialMapTrackingPoint.cs

using Microsoft.MixedReality.Toolkit;
using Microsoft.MixedReality.Toolkit.SpatialAwareness;
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEngine;

public class SpatialMapTrackingPoint : MonoBehaviour
{
    void Update()
    {
        UpdateTransformFromCamera();
    }
    
    /// <summary>
    /// カメラから一定距離になるように位置を更新する
    /// </summary>
    private void UpdateTransformFromCamera()
    {
        // カメラからの距離上限(5m)
        const float modelSetDistance = 5.0f;
        
        // カメラ前方の位置を計算
        var camTransform = CameraCache.Main.transform;
        var camPosition = camTransform.position;
        var targetPosition =
            camPosition +
            camTransform.forward *
            modelSetDistance;
            
        // Spatial Awarenessのレイヤー(31: Spatial Awareness)に対してのみレイキャストの判定を行う
        // 空間認識のオブザーバを取得する
        IMixedRealitySpatialAwarenessMeshObserver spatialAwarenessMeshObserver =
            CoreServices.GetSpatialAwarenessSystemDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();

        // オブザーバからレイヤー番号を取得する
        int meshPhysicsLayer = spatialAwarenessMeshObserver.MeshPhysicsLayer;
        int layerMask = 1 << meshPhysicsLayer;
        
        // カメラからレイキャストを飛ばして途中に障害物があれば、その手前に移動する
        if (Physics.Raycast(camPosition, camTransform.forward, out var hit, modelSetDistance, layerMask))
        {
            targetPosition = hit.point;
        }
        
        // 計算した位置を反映する
        transform.position = targetPosition;

        // オブジェクトをカメラの方向に向ける
        transform.LookAt(camPosition);
    }
}

スクリプトをゲームオブジェクトにアタッチすると、カメラの視点の正面5m以内に空間メッシュが存在すれば、その位置にオブジェクトが追従します。

シーンを再生してシミュレーション上で動作を確認します。
空間メッシュの方向を向くと、スクリプトをアタッチしたオブジェクトが追従します。

SurfaceMagnetismを利用する場合

Raycastを利用する以外にもMRTKのSurfaceMagnetismを利用して視線やハンドレイの衝突位置を追跡することができます。
SurfaceMagnetismを利用する方法については以下の記事を参照ください。
bluebirdofoz.hatenablog.com