MRが楽しい

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

Unityでレイキャストが反応するレイヤーを指定する

本日はUnityの小ネタ枠です。
Unityでレイキャストが反応するレイヤーを指定する方法です。

Physics.Raycast

光線(レイ)を飛ばして直線状の衝突判定をチェックします。
引数からレイの距離や衝突する対象レイヤーの指定が行えます。
docs.unity3d.com

レイヤーを指定する場合、レイヤーマスクを利用します。
レイヤーマスクはビットマスクとしてフォーマットされた整数なので設定方法に注意が必要です。
docs.unity3d.com

LayerMask.GetMaskメソッドを利用するとレイヤー名からレイヤーマスクを作成できます。
docs.unity3d.com

using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        Debug.Log(LayerMask.GetMask("UserLayerA", "UserLayerB"));
    }
}

また指定のレイヤー名以外のレイヤーを対象としたい場合はビットマスクの反転を組み合わせることで指定できます。

using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        // 補数演算子(~)を先頭につけてビット反転することで「指定のレイヤー以外」の指定になる
        Debug.Log(~LayerMask.GetMask("UserLayerA", "UserLayerB"));
    }
}

サンプルスクリプト

スクリーンへのタップからレイキャストを実行する以下のサンプルスクリプトを作成しました。
レイヤーマスクで指定したレイヤーのみ衝突判定が行われます。
・RaycastTargetLayerTest.cs

using UnityEngine;

public class RaycastTargetLayerTest : MonoBehaviour
{
    void Update()
    {
        // ひとつ以上のタッチがある場合
        if (Input.touchCount > 0)
        {
            // 一つ目のタッチを取得
            Touch touch = Input.GetTouch(0);

            // タッチ開始時レイキャストを行う
            if (touch.phase == TouchPhase.Began)
            {
                // ポイント座標からレイを作成する
                Ray ray = Camera.main.ScreenPointToRay(touch.position);
                
                // 対象となるレイヤーを設定する
                LayerMask layerMask = LayerMask.GetMask("TestLayer1", "TestLayer2");
                Debug.Log($"LayerMask : {layerMask.value}");
                
                // 対象レイヤーを設定してレイキャストを行う
                if (Physics.Raycast(ray, out RaycastHit hit, 5f, layerMask))
                {
                    // レイが衝突した場合レイヤー名をデバッグ表示する
                    Debug.Log($"Hit : {LayerMask.LayerToName(hit.collider.gameObject.layer)}");
                    Debug.DrawRay(ray.origin, ray.direction * hit.distance, Color.yellow, 5f);
                }
                else
                {
                    Debug.Log("Not Hit");
                }
            }
        }
    }
}

次に以下の通りレイヤーマスクの部分に補数演算子を追加しました。
こちらの場合、記述したレイヤー名以外のレイヤーでのみ衝突判定が行われます。

                // 対象となるレイヤーを設定する
                LayerMask layerMask = ~LayerMask.GetMask("TestLayer1", "TestLayer2");
                Debug.Log($"LayerMask : {layerMask.value}");
                
                // 対象レイヤーを設定してレイキャストを行う
                if (Physics.Raycast(ray, out RaycastHit hit, 5f, layerMask))