超要約
-
内積(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+Cos はacos 回避で高速。ベクトルは正規化しておくと安全。 |
軸への投影(量/向き) | スカラー: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) |
n̂ は 正規化必須。未正規化だと距離スケールが狂う。 |
パフォーマンスと落とし穴
-
正規化の有無:角度比較や一致度では正規化を徹底。
Project
系は軸を正規化して渡すと安全。 -
Vector3.Angle
は重め:大量判定はDot+Cos
が有利。 -
InverseTransformPoint
は強力:前後(z)/左右(x)/上下(y)を一撃で。 -
Plane.GetDistanceToPoint
:自前の誤差/符号混乱を避けられる。
まとめ
- 内積は“向きの近さ”を即値で得る万能スカラー。
- 同じ発想を
Angle / Project / InverseTransformPoint / Plane
で書き分け可能。 - 正規化 + cos しきい値の型を覚えれば、速くて安定した判定が書ける。