MRが楽しい

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

Physics.queriesHitBackfacesを使って面の裏側にもレイキャストが当たるようにする

本日は Unity の小ネタ枠です。
Physics.queriesHitBackfacesを使って面の裏側にもレイキャストが当たるようにする方法についてです。

Physics.queriesHitBackfaces

Physics.queriesHitBackfaces を有効にすると面の裏側にもレイキャストがヒットします。
デフォルトでは false に設定されており、面の裏側にはレイキャストがヒットしません。
docs.unity3d.com

// 面の裏側も検出する
Physics.queriesHitBackfaces = true;

以下の報告にある通り、一部の Unity バージョンでは本設定が正常に動作しないこともあるようです。
issuetracker.unity3d.com

以下の記事によると Physics.RaycastNonAlloc を利用すると特定のバージョンでも設定が正常に動作するようです。
hacchi-man.hatenablog.com

サンプルシーン

前回記事で作成したサンプルシーンの面を全て裏返してみました。
bluebirdofoz.hatenablog.com

ここでは面の存在が分かりやすいよう Cull off のシェーダを作成して裏面でも面が描写されるようにしています。


以下の[_queriesHitBackface]の設定を変更して裏面の検出可否を切り替えるコンポーネントを作成しました。
・QueriesHitBackfacesTest.cs

using UnityEngine;

public class QueriesHitBackfacesTest : MonoBehaviour
{
    [Header("検出結果")]
    /// <summary>
    /// 水平な床を見つけたか
    /// </summary>
    [SerializeField, Tooltip("水平な床を見つけたか")]
    private bool _isHitHorizontalPlane;
    
    [Header("検出条件")]
    /// <summary>
    /// 面の裏側も検出するか
    /// </summary>
    [SerializeField, Tooltip("面の裏側も検出するか")]
    private bool _queriesHitBackfaces;

    /// <summary>
    /// 許容する角度の誤差
    /// </summary>
    [SerializeField, Tooltip("許容する角度の誤差")]
    private float _approximatelyAngle;
    
    private RaycastHit[] _raycastHits = new RaycastHit[1];
    
    void Update()
    {
        // 面の裏側も検出するか
        Physics.queriesHitBackfaces = _queriesHitBackfaces;
        
        // オブジェクトの直下にレイキャストがヒットするか
        var ray = new Ray(transform.position, Vector3.down);
        var hit = Physics.RaycastNonAlloc(ray, _raycastHits, 1.0f);
        Debug.Log($"hitcount: {hit}");

        // 平面が検出できたか
        if (hit > 0)
        {
            // 平面の法線をチェックして法線が垂直上方向か下方向に向いていれば水平な床と判定する
            var hitNormal = _raycastHits[0].normal;
            var angle = Vector3.Angle(hitNormal, Vector3.up);
            _isHitHorizontalPlane = angle <= _approximatelyAngle || angle >= 180.0f - _approximatelyAngle;
        }
        else
        {
            _isHitHorizontalPlane = false;
        }
    }
}

シーンを再生して動作を確認します。
以下の通り、[_queriesHitBackface]を切り替えると裏返った面の検出が有効/無効化されました。