コンテンツにスキップ

レイと球の衝突判定

let oc = ray.origin - self.position;
let a = ray.direction.length_squared();
let half_b = oc.dot(ray.direction);
let c = oc.length_squared() - self.radius * self.radius;
let discriminant = half_b * half_b - a * c;
  1. 準備する方程式

    • 球の方程式: (PC)(PC)=r2(P - C)・(P - C) = r^2
      • P: 球の表面上の点
      • C: 球の中心
      • r: 球の半径
    • レイの方程式: P=A+tbP = A + tb
      • A: レイの始点
      • b: レイの方向ベクトル
      • t: 始点Aからの距離
    • レイの方程式が表すのは、「始点 A から b 方向に t だけ進んだ位置にある点」となる。この点 P が球の表面上にもある、というのが「衝突」を意味する。
  2. 代入して t の方程式を作る

    球の方程式に含まれる P をレイの方程式 A + tb で置き換える。

    ((A+tb)C)((A+tb)C)=r2((A+tb)−C)⋅((A+tb)−C)=r^2

    この式の目的は、未知数 t を見つけ出すことである。t の値が分かれば、P = A + tb に代入して交点の座標を特定できる。

  3. 展開して整理する

    この方程式を t についての二次方程式 at^2 + bt + c = 0 の形に整理していく。

    まず、式を少し並べ替える。

    ((AC)+tb)((AC)+tb)=r2((A−C)+tb)⋅((A−C)+tb)=r^2

    ドット積を展開する(分配法則が使える)。

    (tb)(tb)+2(tb)(AC)+(AC)(AC)=r2(tb)⋅(tb)+2(tb)⋅(A−C)+(A−C)⋅(A−C)=r^2

    t を外に出して整理する。

    (bb)t2+2(b(AC))t+(AC)(AC)r2=0(b⋅b)t^2+2(b⋅(A−C))t+(A−C)⋅(A−C)−r^2=0

    これで、at2+bt+c=0at^2 + bt + c = 0 の形になった。それぞれの係数は以下のようになる。

    • a=bba = b・b
    • b=2(b(AC))b = 2(b・(A - C))
    • c=(AC)(AC)r2c = (A - C)・(A - C) - r^2
  4. t について解く

    この二次方程式を解の公式を使って解くことで、t の値を求めることができる。

    • 解が2つ: レイが球を貫通する(入口と出口の2点で交差)。
    • 解が1つ (重解): レイが球の表面に接する。
    • 実数解なし: レイは球に当たらず、通り過ぎる。

t の値が求まれば、それがレイの始点から交点までの距離となる。通常は、正の最小値の t を採用して、最も近い交点の座標 P を計算する。