$リアルタイムCGの基礎+Android

レイキャスティング(Ray-casting)

視点から光(ray)を投げかけ(casting)し交差点を求める方法




~球体と直線との衝突式を求める~

Z軸の正方向が奥行きにする。

レイを飛ばす方向をE(Ex,Ey,Ez)とする。(単位ベクトル)

レイを飛ばす座標をP(Px,Py,Pz)とする。

球の座標をS(Sx,Sy,Sz)とする。

球の半径をrとする。

最終的にもとめる、レイと球の衝突座標をQ(Qx,Qy,Qz)とする。

リアルタイムCGの基礎+Android


レイ(光線)と球との当たり判定を取る。

レイに関して、【パラメータ形式】の直線の方程式(y = ax + b)を当てはめる。

Q = E*t + P ...(1)

Pの位置から、Eの方向へ、t進んだところでQに到達することになる。

進んだ距離tを求めればQが求められる。

不明な変数がtとQの二つがあるため、連立二次方程式を使って求めるため、もうひとつ球の式を持ってくる。

球については、【陰関数形式】の球の方程式(x^2 + y^2 + z^2 = r^2)を当てはめる。

(Qx - Sx)^2 + (Qy - Sy)^2 + (Qz - Sz)^2 = r^2 ...(2)


(2)式に(1)式を代入する。

(Ex*t + Px - Sx)^2 + (Ex*t + Px - Sy)^2 + (Ex*t + Px - Sz)^2 = r^2

式の簡略化
x = Px - Sx
y = Py - Sy
z = Pz - Sz
とする。
(Ex*t + x)^2 + (Ex*t + y)^2 + (Ex*t + z)^2 = r^2

まず(Ex*t + x)^2に関してだけ展開
(Ex*t + x)^2
= (Ex*t + x)*(Ex*t + x)
= (Ex*t)^2 + 2*(Ex*t)*x + x^2
= (Ex^2)*t^2 + 2*t*(Ex*x) + x^2

全部を展開、
(Ex^2)*t^2 + 2*t*(Ex*x) + x^2
+ (Ey^2)*t^2 + 2*t*(Ey*y) + y^2
+ (Ez^2)*t^2 + 2*t*(Ez*z) + z^2
= r^2

更に、
= (Ex^2 + Ey^2 + Ez^2)*t^2 + 2*t*(Ex*x + Ey*y + Ez*z) + (x^2 + y^2 + z^2) =r^2

更に、
a = (Ex^2 + Ey^2 + Ez^2) = 1 (Eは単位ベクトルなので1)
b = (Ex*x + Ey*y + Ez*z)
t^2 + 2*t*b + (x^2 + y^2 + z^2) = r^2

更に、(x^2 + y^2 + z^2)を右辺に移動し、両辺にb^2を足す
t^2 + 2*t*b + b^2 = r^2 - (x^2 + y^2 + z^2) + b^2

左辺を因数分解
(t + b)^2 = r^2 - (x^2 + y^2 + z^2) + b^2

両辺を√
t + b = ±sqrt(r^2 - (x^2 + y^2 + z^2) + b^2)

bを右辺に移動
t = ±sqrt(r^2 - (x^2 + y^2 + z^2) + b^2) - b

tを選択。
$リアルタイムCGの基礎+Android
球の表面との交差点
t1 = -sqrt(r^2 - (x^2 + y^2 + z^2) + b^2) - b
球との裏面との交差点(E Nベクトルが交差していない)
t2 = +sqrt(r^2 - (x^2 + y^2 + z^2) + b^2) - b

t1>0 & t2>0 Pより前(E方向)に球がある
t1<0 & t2>0 球の中にPがある
t1<0 & t2<0 Pの後ろに球がある


まとめ
x = Px - Sx
y = Py - Sy
z = Pz - Sz
b = (Ex*x + Ey*y + Ez*z)
t = -sqrt(r^2 - (x^2 + y^2 + z^2) + b^2) - b