Unityには、指定された位置から指定された向きに向かう光線(レイ)を表現するRay構造体があります。
Ray構造体は、レイキャストでオブジェクトを検知したい場合に使われることで馴染み深いかもしれません。
しかし、Ray構造体自体にはレイキャストの機能は無く、あくまで始点と向きの情報を持ったデータです。
視点と向きセットで管理したい場合は、Ray構造体を用いるとソースコードの見通しが良くなる場合があります。
Ray構造体を使わない場合
var origin = transform.position;
var direction = new Vector3(1, 2, 3).normalized;
Ray構造体を使った場合
var ray = new Ray(
transform.position,
new Vector3(1, 2, 3)
);
上記はどちらも同じ処理を行っています。
具体的にどうやって使うの?
基本的な使い方から、いくつか使用例も見ていくね。
本記事では、Ray構造体の仕様と使用例を紹介します。
- Unity2021.2.0f1
Ray構造体の仕様
原点と向きの2つのフィールドを持つ構造体です。
次のようにインスタンス化して使います。
// レイの原点
var origin = new Vector3(1, 2, 3);
// レイの向き
var direction = new Vector3(4, 5, 6);
// レイをインスタンス化
var ray = new Ray(origin, direction);
// レイの内容を出力
Debug.Log($"Ray = {ray}");
なお、Ray構造体に格納される向きベクトルは、必ず長さ1に正規化されます。
そのため、Ray構造体に指定する向きベクトルを、呼び出し元で正規化する必要がありません。 [1] ただし、長さがほぼ0のベクトルが指定された場合はdirectionが零ベクトルになってしまう点には注意が必要です。
また、Ray構造体に格納される原点と向きは、それぞれorigin、directionプロパティとしてアクセス可能です。
// レイの原点を指定
ray.origin = new Vector3(1, 2, 3);
// レイの向きを指定(正規化して格納される)
ray.direction = new Vector3(4, 5, 6);
このdirectionプロパティから向きを指定した際も、内部的にベクトルが正規化されます。
レイの原点から一定距離進んだ位置を取得する
レイの原点から指定された距離だけ進んだ位置は、Ray.GetPointメソッドで得られます。
public Vector3 GetPoint(float distance);
引数distanceには、レイの原点から進む距離を指定します。負の値が指定された場合は、レイの向きとは逆向きに進むという意味になります。
レイ(緑)と戻り値(赤)を可視化すると次のようになります。
Ray構造体の活用例
Ray構造体がよく出てくると思われる活用例を紹介します。
コライダーのレイキャスト
画面でクリックされた位置にオブジェクトが存在するかをチェックするサンプルです。
using UnityEngine;
public class RaycastExample : MonoBehaviour
{
private void Update()
{
// マウスが左クリックされたら
if (Input.GetMouseButtonDown(0))
{
// クリック位置のレイを取得
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// コライダーとレイとの当たり判定
if (Physics.Raycast(ray, 100))
{
print("コライダーがクリックされた!");
}
}
}
}
画面でクリックされた位置からレイを飛ばし、レイにヒットするコライダーが存在したらデバッグログを出力します。
クリック位置から伸びるレイを表現するためにRay構造体を使用しています。
// クリック位置のレイを取得
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// コライダーとレイとの当たり判定
if (Physics.Raycast(ray, 100))
{
print("コライダーがクリックされた!");
}
平面との交点判定
Plane構造体とRay構造体を使って、平面とレイとの当たり判定ができます。
コードの概略は次のようになります。
Transform planeObject;
Transform rayObject;
・・・(中略)・・・
// 平面を定義
var plane = new Plane(planeObject.up, planeObject.position);
// レイを定義
var ray = new Ray(rayObject.position, rayObject.forward);
// レイと平面との当たり判定
// ヒットした場合はenterに平面までの距離が格納される
var isHit = plane.Raycast(ray, out var enter);
// ヒットした位置
var point = ray.GetPoint(enter);
使い方の詳細は、以下記事をご覧ください。
さいごに
Ray構造体は指定された点から指定された向きに伸びるレイを表現するためのものです。
いくつかのUnity APIでは、Ray構造体を引数として要求するものも存在します。
Ray構造体を使うと、点と向きの2つの変数をペアで管理したり、向きの正規化に気を付ける必要がある問題を解決してくれます。