Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
14
Help us understand the problem. What is going on with this article?
@OKsaiyowa

【Unity(C#)】Rayではなく内積(Vector3.Dot)で視線判定を行う

More than 1 year has passed since last update.

視線

VRで視線判定をけっこう使うのでメモしときます。

Rayを使用した視線の判定も十分簡単にできます。
"目(カメラ)からビーム出してビームがターゲットに衝突したら処理を行う"
ただこれだけです。

ただし、障害物があるとLayerやTagで衝突を避ける設定をする必要があります。

今回は会社の上司に教えてもらった
LayerやTagを一切気にしなくてもいい方法で実装してみようと思います。

内積

まずは内積とは何かを一言で説明したいのですが、
一言で表すとなると全く思いつきませんでした。

私の理解もその程度だということなので、複数のリンクを貼っておきます。
個人的に動画の解説が一番しっくりきました。

Qiita記事 :【数学】「内積」の意味をグラフィカルに理解すると色々見えてくる その1

Youtube : 喋り方の癖だけ耐えればめちゃめちゃわかりやすい動画

Youtube : シンプルにわかりやすい動画

コード

たったこれだけです。

カメラにアタッチ
using UnityEngine;

public class Dot : MonoBehaviour
{
    [SerializeField]
    Transform targetTransform;

    Transform cameraDirection;

    void Start()
    {
        cameraDirection = this.gameObject.GetComponent<Transform>();
    }

    void Update()
    {
        //ターゲットからカメラの方向へ正規化したベクトルを作成
        Vector3 targetToCameraDirection_N = (cameraDirection.position - targetTransform.position).normalized;

        //正規化したベクトルの内積が一定以下なら見たことにする
        if (Vector3.Dot(targetToCameraDirection_N, cameraDirection.forward.normalized) < -0.9)
        {
            print("見た!");
        }
    }
}

normarized

ベクトルを正規化してくれます。
問答無用で値を1にしてくれるってことです。(ただし小さすぎると0になるので注意)

normarizedを利用することで、2点の位置から算出したベクトルを
常に一定の大きさで取得することができます。

Vector3.Dot

二つのベクトルを渡してあげるだけで内積を返してくれます。(参考リンク)
B292E9AE-1C23-44DB-8684-C87F4EEC9C84.png

lhs,rhsはLeft(Right) hand sideの略らしいです。

今回はVector3.Dotを利用して内積が-0.9(約cos155°)以下になると見たという判定にしています。

人間の有効視野の上限は20~30度だといわれている1ので
完全に視線が一致(内積が-1(cos180°))するまで判定させないより
だいたいこの辺りを見たと判断させる方が良い方法だと思います。

・ターゲットの位置からカメラの位置へ向けたベクトル
・カメラの正面方向(Z軸正の向き)のベクトル
↑これらのベクトルから内積を計算してます。

デモ

視線判定の範囲内に入ると赤色に変わるようにしたデモです。

Gif_Dot.gif

-0.9-0.95のように-1に近づけてあげるともっと厳格な視線判定もできます。
  

大学はおろか高校ですら ろくに数学をやってこなかったので間違いがあれば
遠慮なくご指摘ください。

視錐台

2019/11/08 追記

興味深い記事を見つけたので関連として貼っておきます。
【Unity】【数学】視錐台(Frustum)について(第2回)

視錐台の内判定 = 見えている範囲 = Unityのカメラの描画範囲VR(HMD越し)の視界
なので、VRへの応用は許容誤差が範囲内であれば、、、といった感じでしょうか。

logicalbeat様 記事引用
// 視錐台平面を獲得
Plane[] planes = GeometryUtility.CalculateFrustumPlanes( camera );
System.Array.Resize( ref planes, 4 );       // near,far面を排除

// 内外判定
if ( GeometryUtility.TestPlanesAABB( planes, bounds ) ) {
    // 入った!!
}

  1. 参考リンク  

14
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
OKsaiyowa
備忘録として学んだことを記録します。 あやふやな箇所が多いですが、そんなときはビシッと指摘いただけますと幸いです。
unity-game-dev-guild
趣味・仕事問わずUnityでゲームを作っている開発者のみで構成されるオンラインコミュニティです。Unityでゲームを開発・運用するにあたって必要なあらゆる知見を共有することを目的とします。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
14
Help us understand the problem. What is going on with this article?