4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unityで“内積”を使い倒す

Last updated at Posted at 2025-09-08

超要約

  • 内積(Dot)は「向きの一致度」を単一のスカラーで返す:+1 同じ / 0 直交 / -1 逆
  • 角度しきい値比較、前後判定、投影(軸成分の抽出)、平面の符号付き距離などゲーム実装の芯に刺さる。
  • Unity 標準 API:Vector3.Dot / Vector2.Dot / Vector3.Angle / Vector3.Project / Vector3.ProjectOnPlane / Transform.InverseTransformPoint / Plane.GetDistanceToPoint など。

使いどころ

1) 視野(FOV)チェック:「目の前にいる?」

  • 何が決まる? 前方コーン(半角度=FOV/2)内にターゲットが入っているか。
  • どんなシーン? 敵AIの検知、ロックオン候補の絞り込み。
bool IsInFOV(Transform self, Transform target, float fovDeg)
{
    Vector3 toTarget = (target.position - self.position).normalized;
    float cosHalf = Mathf.Cos(0.5f * fovDeg * Mathf.Deg2Rad);
    return Vector3.Dot(self.forward, toTarget) >= cosHalf;
}

self.forward は Transform のローカル+Z(正規化済み)。一般ベクトルは正規化して扱うと安全です。

Unityの便利メソッドで書くなら(Vector3.Angle

bool IsInFOV_Angle(Transform self, Transform target, float fovDeg)
{
    float ang = Vector3.Angle(self.forward, target.position - self.position);
    return ang <= fovDeg * 0.5f;
}

2) 前後判定:「プレイヤーから見て前か?」

  • 何が決まる? self.forward(ローカル+Z)に対して点が前(+)か後(-)か。
  • どんなシーン? 近接攻撃の当たり側、UI誘導、カメラの補間方向制御。
bool IsInFront(Transform self, Vector3 point)
{
    Vector3 toPoint = (point - self.position).normalized;
    return Vector3.Dot(self.forward, toPoint) > 0f; // 正: 前 / 負: 後
}

Unityの便利メソッドで書くなら(Transform.InverseTransformPoint

bool IsInFront_LocalZ(Transform self, Vector3 point)
{
    return self.InverseTransformPoint(point).z > 0f;
}

3) 接近/離反の判定(相対速度 × 相対位置)

  • 何が決まる? ふたりの距離がこの瞬間“縮むか/広がるか”。
  • どんなシーン? 追尾や回避AI、衝突予測、ヒットストップの条件分岐。
bool IsApproaching(Vector3 myPos, Vector3 myVel, Vector3 targetPos, Vector3 targetVel)
{
    Vector3 relPos = targetPos - myPos;
    Vector3 relVel = targetVel - myVel;
    return Vector3.Dot(relVel, relPos) < 0f; // 負なら距離が縮む
}

4) 投影:「軸に沿った量」「軸成分を除去」

  • 何が決まる? ベクトルの“この軸に沿った量(スカラー/ベクトル)”や“軸成分の削除”。
  • どんなシーン? 前向き速度の抽出、斜面に沿う移動、壁面へのスライド。
float ComponentAlongAxis(Vector3 v, Vector3 axisNormalized)
{
    return Vector3.Dot(v, axisNormalized);
}

ProjectOnPlane の第2引数は平面の法線(= 除去したい軸の法線)です。

Unityの便利メソッドで書くなら

Vector3 AlongVec(Vector3 v, Vector3 axisNormalized)
    => Vector3.Project(v, axisNormalized);

Vector3 RemoveAlong(Vector3 v, Vector3 normalNormalized)
    => Vector3.ProjectOnPlane(v, normalNormalized);

5) 角度しきい値で重み付け(ロックオン/照準)

  • 何が決まる? 「正面度」を 0..1 に正規化した重み(近いほど高得点)。
  • どんなシーン? 照準アシスト、ターゲット優先順位付け、UIのハイライト強度。
float AimScore(Transform self, Vector3 targetPos)
{
    Vector3 dir = (targetPos - self.position).normalized;
    float d = Mathf.Clamp01((Vector3.Dot(self.forward, dir) + 1f) * 0.5f); // 0..1
    return d * d; // 好みでカーブ
}

Unityの便利メソッドで書くなら

float AimScore_Angle(Transform self, Vector3 targetPos, float fovDeg=120f)
{
    float half = fovDeg * 0.5f;
    float ang = Vector3.Angle(self.forward, targetPos - self.position);
    float t = Mathf.InverseLerp(half, 0f, ang); // 視線に近いほど1
    return t * t;
}

6) スロープ可否(立てる/滑る)の判定

  • 何が決まる? 地面法線と上向きの角度が許容内か。
  • どんなシーン? キャラの坂移動、足場の設計、移動可能ナビメッシュ制限。
bool CanStandOn(Vector3 groundNormal, float maxSlopeDeg)
{
    float cosLimit = Mathf.Cos(maxSlopeDeg * Mathf.Deg2Rad);
    return Vector3.Dot(groundNormal.normalized, Vector3.up) >= cosLimit;
}

Unityの便利メソッドで書くなら

bool CanStandOn_Angle(Vector3 groundNormal, float maxSlopeDeg)
{
    return Vector3.Angle(groundNormal, Vector3.up) <= maxSlopeDeg;
}

7) 速度の“前向き成分”だけを使う

  • 何が決まる? 自分の forward 方向へ押し出す速度(後ろ向きは 0)。
  • どんなシーン? キャラの前進のみ許可、乗り物の推進力制御、アシスト移動。
Vector3 ForwardOnlyVelocity(Transform self, Vector3 velocity)
{
    float forwardMag = Mathf.Max(0f, Vector3.Dot(velocity, self.forward));
    return self.forward * forwardMag;
}

8) ランバート拡散(簡易ライティング)

  • 何が決まる? 光線方向と法線のなす角に応じた明るさ(負側は 0)。
  • どんなシーン? シェーダ/擬似ライティング、UIの向きによるフェード。
float Lambert01(Vector3 normal, Vector3 lightDirNormalized)
{
    return Mathf.Max(0f, Vector3.Dot(normal.normalized, lightDirNormalized));
}

9) 平面の符号付き距離(面のどちら側?)

  • 何が決まる? 点が平面の法線側か反対側か、そして距離(符号付き)。
  • どんなシーン? 範囲外消去、ポータル面通過判定、ダメージゾーンの境界。
float SignedDistanceToPlane(Vector3 point, Vector3 nNormalized, float d)
{
    return Vector3.Dot(nNormalized, point) + d; // 正: 法線側 / 負: 反対側
}

nNormalized は正規化済み、d は平面方程式 n̂·x + d = 0 の定数です(未正規化だと距離スケールが狂います)。

平面上の既知点 pointOnPlane があれば d = -Dot(nNormalized, pointOnPlane) と置けます。

Unityの便利メソッドで書くなら

Plane pl = new Plane(nNormalized, pointOnPlane);
float sd = pl.GetDistanceToPoint(point); // 正=法線側

10) 並べ替え:「自分から見て正面度の高い順」

  • 何が決まる? 自分から見た“前向き度”の高い順序でターゲットを並べる。
  • どんなシーン? ロックオン対象リスト、UIの優先表示、サーチ結果の整列。
enemies.Sort((a, b) =>
{
    Vector3 sa = (a.position - self.position).normalized;
    Vector3 sb = (b.position - self.position).normalized;
    return Vector3.Dot(self.forward, sb).CompareTo(Vector3.Dot(self.forward, sa));
});

Unityの便利メソッドで書くなら

enemies.Sort((a, b) =>
    self.InverseTransformPoint(b.position).z.CompareTo(
        self.InverseTransformPoint(a.position).z));

2Dでも同じ(Vector2)

  • 右向き成分:Vector2.Dot(vel, Vector2.right) > 0
  • 角度/視野:Vector2.Angle(forward, toTarget) <= halfFov
  • 左右判定:Vector2.SignedAngle(a, b) の符号(正=反時計回り)
bool IsOnRight(Vector2 from, Vector2 toDir)
{
    float signed = Vector2.SignedAngle(from.normalized, toDir.normalized);
    return signed < 0f; // 右側
}

Unityの規約:反時計回り(CCW)が正、時計回りが負。


API早見表(内積 ⇔ Unity標準)

目的/用途 数式・概念 Unity標準API 注意点
角度しきい値判定 Dot(a, b) >= cos(θ) Vector3.Angle(a, b) <= θ Dot+Cosacos回避で高速。ベクトルは正規化しておくと安全。
軸への投影(量/向き) スカラー:Dot(v, â) ベクトル:Vector3.Project(v, â) â は正規化推奨。スカラー値が欲しいかベクトルが欲しいかで使い分け。
軸成分の除去 v - Project(v, â) Vector3.ProjectOnPlane(v, â) â は法線方向。数値安定のため正規化が無難。
前後/左右/上下の判定 Dot(dir, forward/right/up) の符号 Transform.InverseTransformPoint(p).z/x/y InverseTransformPoint は一発でローカル符号が取れて可読性◎。
平面からの符号付き距離 Dot(n̂, p) + d new Plane(n̂, pointOnPlane).GetDistanceToPoint(p) 正規化必須。未正規化だと距離スケールが狂う。

パフォーマンスと落とし穴

  • 正規化の有無:角度比較や一致度では正規化を徹底。Project 系は軸を正規化して渡すと安全。
  • Vector3.Angle は重め:大量判定は Dot+Cos が有利。
  • InverseTransformPoint は強力:前後(z)/左右(x)/上下(y)を一撃で。
  • Plane.GetDistanceToPoint:自前の誤差/符号混乱を避けられる。

まとめ

  • 内積は“向きの近さ”を即値で得る万能スカラー
  • 同じ発想を Angle / Project / InverseTransformPoint / Plane で書き分け可能。
  • 正規化 + cos しきい値の型を覚えれば、速くて安定した判定が書ける。
4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?