まずレイトレの四角形の当たり判定を行なう前によくある球の当たり判定をおさらいしてみます



絶対必要なのが視線方向ベクトルと視線位置ベクトル


方向ベクトルは視線がどこの方向を向いているか、x、y、z、成分の3つの値で設定します

位置ベクトルはx、y、z、の位置をあらわしているベクトルです



視線方向をVベクトル、視線位置をMベクトルとし、判定をする球の中心位置ベクトルをQベクトル、球の単位ベクトルをP、半径をrとします


※VとPは単位ベクトル

4b8b9221.png




あとは数Bでやったハズの交点を求める計算をします。


球と線分の交点はベクトルVに変数tを掛けてtVとし、それが位置Qから見てrの距離に存在できるかを考えます。



上の図から Q+rP=M+tV


という式が立てられます

注意したいのはPベクトルの向きが決定されてないのでx、y、zの成分を3つ比べて連立方程式を解く

という方法は使えません。


なので |P|=1.0 という条件をうまく使って解くことを考えます

P^2 (Pの2乗) は1なので


r^2=(rP)^2=(M+tV-Q)^2  ・・・・・①


という式が立てられます。

MとQはすでにx、y、zの成分が決定しているので新しいベクトルHをつくり


H=M-Q


として①に代入&変形し


(H+tV)^2-r^2=0    ・・・・・・②


と t の2次方程式を作り、解の公式を使って t を求めます。

②を展開し


t^2 + 2tH・V + H^2 - r^2 = 0    ・・・・③


これで、ニーエーブンノ・・・の公式が使えますね


a=1

b=2H・V

c=H^2-r^2


bはベクトル同士の掛け算が入っているので内積を使います

H=(x1,y1,z1)

V=(x2,y2,z2)

のとき

H・V=x1*x2 + y1*y2 + z1*z2

です。


またbが2の倍数なので

b'=b/2  とおき


エーブンノマイナスビーダッシュ・・・の公式を使って


t=( -b'±√b'^2-ac ) / a


ここで t は0、1つまたは2つの解をもつことが判明します。


2つの場合は交点が2つ、すなわち球に視線が刺さっているような状態です。

1つの場合は接していると言えます。

0の場合は交点がありません。



また解が虚数でなくても t は正でなければいけないし

交点が2つの場合は

視線は球の奥じゃなく手前の交点で反射してますから解の公式の±の部分は-であると決定できます。

t は図の通り視線の長さです。


さてここまでが思考上の筋道です。

数学が絡むアルゴリズムを考える場合は、プログラムをいきなり書き始める前にこのように思考上で筋道を作ることが絶対必要です。





では、これらをプログラムでやってみましょう。



計算するに当たり初期状態で必要な変数は

ベクトルV、M、Qのx、y、z成分の値を記憶している変数です。

その変数はこのブログでは仮にVx,Vy,Vz,Mx・・・・・・とします。





Hx=Mx-Qx

Hy=My-Qy

Hz=Mz-Qz

b=Hx*Vx + Hy*Vy + Hz*Vz           ;内積の計算で解の公式のbに出力

c=Hx*Hx + Hy*Hy + Hz*Hz - r*r       ;ベクトルの距離の計算で解の公式のcに出力

D4=b*b-c                      ;解の公式の4分のDに出力

if D4<0.0:gosub*交点なし処理          ;ルートの中がマイナスのとき条件分岐

t=-b-sqrt(d4)

if t<0.0:gosub*交点なし処理           ;交点はあるが視点の後ろにある場合条件分岐

gosub*交点あり処理               ;視線と球が当たった時の処理、交点の位置はM+tV








以上が当たり判定部分の計算プログラムです。

紙の上で計算したときより、いらない計算や式は全部省いているので相当短くっています。


結果的にPベクトルは使わないので最初に設定しておく必要もなくプログラム上では変数を作る必要がありません。



交点がない場合はまた別の球と当たり判定をします

全ての球とぶつからなく、視線が地面or空まで伸びる場合はその色を、画面のドットの色として出力します。




交点がある場合は、入射してくる光線のベクトルを決定するためにまた別の計算を行わなければいけません。

その計算とは法線の計算です。

入射ベクトルを求めるには以下の図のように法線ベクトルを求める必要があります。

f8b0024f.png


法線ベクトルは球の中心から交点までのベクトルを単位ベクトルに変換すれば完成です。

-入射ベクトルを求める計算は図のように


-入射ベク = cos(θ) × 法線ベク × 2 + 視線ベク


ですぐ求まります。


cos(θ)は法線ベクと視線ベクの内積に等しいです。(ただし両方単位ベクトルでないといけない)



そして入射ベクトルが求まれば、視点位置=交点、視線ベクトル=-入射ベクトル、としてカメラの位置と方向を改めて決定し、再度当たり判定処理をすればいつかは地面or空に当たるときが来ますので、それまで何回もループさせます。

(処理が重い場合は反射の回数制限をする場合もある)