面と線の当たり判定(概要編)

面と線の当たり判定

面と線の当たり判定について解説します。

当たり判定で必要な情報は交点(当たる位置)の算出です。
では交点を求める方法を実装していきましょう。

1.交点を求める式

始点(p)から向き(vec)を伸ばした時に面(p1, p2, p3)と交差する点(p’)を求める計算は下記になります。
① p’ = p + vec * t

交点(p’)を求めるには始点(p)と向き(vec)は分かっていますが長さ(t)が分かっていません。
なので先ずは長さ(t)を求める必要があります。

2.交点までの長さを求める方法

交点までの長さ(t)を求めるには三角関数を使います。
式:cosθ = c / a

では始点(p)から面(p1, p2, p3)に垂直な線(n)と長さ(|n|)が分かれば長さ(t)が出せます。
これを三角関数の式に置き換えます。
式:cosθ = |n| / t

これを t を解く式に変換すると
② t = |n| / cosθ

この式を解ければ長さ(t)が出るので交点(p’)が出せます。

ただ、このcosθと面(p1, p2, p3)に垂直な線(n)の長さ(|n|)がまだ分かりません。

3.面と垂直な線を求める方法

面と垂直な線の向きは面の法線と同じです。
面の法線を求めるには外積を使います。
式:axb = |a||b|sinθの長さを持った垂直な線

面の辺1(p2 – p1)と辺2(p3 – p1)で外積を行えば垂直な線が出ます。
③ (p2 – p1)x(p3 – p1) = |(p2 – p1)||(p3 – p1)|sinθの長さを持った垂直な線

この式で出たベクトルを正規化すれば垂直な線(n)の向きが求められます。
※外積の順番でベクトルの向きが逆になるので気を付けてください。

4.面と垂直な線の長さを求める方法

次に垂直な線(n)の面までの長さ(|n|)を三角関数で求めます。
これは2と同じです。
式:cosθ = c / a

では始点(p)から面を構成する点(p1)を繋ぐ線(p1 – p)と求める長さ(|n|)を三角関数の式に置き換えます。
式:cosθ = |n| / |(p1 – p)|

|n|を解く式に変換すると
④ |n| = |(p1 – p)|cosθ

この時のcosθは内積で算出することが出来ます。
式:a・b = |a||b|cosθ

それぞれを今回の情報に置き換えます。
式:n・(p1 – p) = |n||(p1 – p)|cosθ

この時の|n|は垂直な線(n)を正規化しておけば消すことが出来ます。
式:n・(p1 – p) = |(p1 – p)|cosθ

この時、右の式が|n|を解く式④と一致しました。

つまり④を元に置き換えることで|n|を求める式が出来ます。
⑤ |n| = n・(p1 – p)

※絵で見ると直角になっていないように見えますが、3Dなので真横から見ると垂直になります。

5.交点までの長さを求める方法(完結編)

②では式を作っただけで不明な値がいくつかありました。
式:t = |n| / cosθ

ただ⑤で|n|の式は出たので置き換えてみましょう。
式:t = (n・(p1 – p)) / cosθ

後、必要なのは cosθだけです。
これも内積で出すことができます。

では始点から向き(vec)と面に垂直な線(n)を当てはめます。
式:vec・n = |vec||n|cosθ

それぞれ正規化してあれば長さが消えるので
⑥ vec・n = cosθ

最後にこの式も t を解く式に当てはめると
⑦ t = (n・(p1 – p)) / (vec・n)

これで交点までの長さ(t)が出ます。

6.交点の算出(実計算)

①で交点を求める式を書いていました。
式:p’ = p + vec * t

これに必要な情報がすべてそろったので、
後は⑥の式を解いた結果を使って実際に計算をするだけです。
式:p’ = p + vec * t

これを解けば面(p1, p2, p3)と水平などこかで衝突する点(p’)が取れます。
ただし、面の3点(p1, p2, p3)の内にあるか外にあるかはまだ分かりません。

7.衝突する点(p’)が面の中にあるかの判定

面と水平な位置に衝突する点(p’)は分かりましたが、
3点(p1, p2, p3)の外側にある可能性があります。

なので内側にあるかを判定する必要があります。

内か外かの判定は面をなす三角形の3つの辺とそれぞれの点と交点(p’)を繋いだ線で外積をとって、
面に垂直な線を出します。
そして出た垂直な線と法線(n)の内積を取ります。

その時の結果が全て0以上か0以下のどちらかになれば内側にあることになります。
0以下か0以上かは外積をとる際の向きによって変わります。

式:(p1 – p’)x(p2 – p1) = |(p1 – p’)||(p2 – p1)|sinθ = 垂直な線(vec1)
式:(p2 – p’)x(p3 – p2) = |(p2 – p’)||(p3 – p2)|sinθ = 垂直な線(vec2)
式:(p3 – p’)x(p1 – p3) = |(p3 – p’)||(p1 – p3)|sinθ = 垂直な線(vec3)

次に内積でそれぞれ判定します。

式:vec1・n = |vec1||n|cosθ
式:vec2・n = |vec2||n|cosθ
式:vec3・n = |vec3||n|cosθ

この内積の結果、cosθが0以上の値であれば全て内側にあるということになります。

8.本当に衝突した面か?

メッシュには面が沢山あるので当たった面の他にも当たる面があるかもしれません、
なので当たった場合もそこで終了せずに他の面が手前にあるかをループでチェックしていきます。

当たった際は当たった点(p’)と視点からそこまでの距離|p’ – p|を保持します。
全ての面を回した際に一番近い距離で当たった点が衝突点です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です