N88-BASICでレイトレーシング (1回目)
2021/6/1(火)
N88-BASICでレイトレーシング (1回目)
(by ULproject for N88-BASIC, NL-BASIC)
レイトレーシングで球を表示するという
簡単なプログラムをN88-BASICで作ります
速度や色数に問題がありますのできれいな画面
を描画する事より、動作原理を理解することが
目的です
とその出発点V(視点位置ベクトル)
レイトレーシングは他の方法に比べて簡単です
上図1のように視線と球の1番近い交点の色が
見えているので、その色をスクリーン上に描いて
行くという仕組みです
ちなみに、図1の視点の位置は、z軸上にとる
場合と、スクリーン上の点(図のV)にとる場合が
ありますが、Vを視点とした場合は、球が
スクリーンに重なったとき、球をスクリーンで
切断した断面を描くことができますが、
z軸上の場合は断面を描くことはできません。
ここでは前者のやり方で進めていきます。
まず、視点から球までの距離を求めます。
ここから、数値(スカラー)を小文字、ベクトル
(x,y,z成分を持つ矢印)を大文字で描くこと
にします。
P:任意の位置ベクトル
r:球の半径
V:視点の位置ベクトル
E:視線の方向単位ベクトル
t:任意の値
とします。位置ベクトルPは点Pと同じような
ものだと思って下さい。Eは方向を表し、単位
ベクトルは距離(矢印の長さ)が1のベクトルで、
|E| = 1と書きます。|E|はEベクトルの長さです。
図1を参考にして下さい
原点が中心で半径rの球は、
|P| = r
で表されます。
原点から点Pまでの長さがrの点の集まりです
ので、球になります。
視点VからE方向に向けた視線は、
P = V + Et
で表されます。
点VからE方向に任意の距離t離れた点Pの集まり
ですので、点Vを通りE方向に平行な直線になります。
ここで、余談ですが、
任意の場所にある球は、中心の位置を点Cとすると、
|P - C| = rとなりますが、視線の方は視点が
移動してもP = V + Etと変わりませんので、
球と視線を移動して球を原点に持ってくれば、
|P| = rの式で求めることができます。
よって、|P - C| = rは必要なく
次の2式で十分です
|P| = r
P = V + Et
この式から視点と球間の距離tを求めます。
|P| = r にP = V + Etを代入
|V + Et| = r の絶対値記号を外すため両辺を2乗
(V + Et)(V + Et) = r2 を展開
V・V + 2(V・E)t + (E・E)t2 = r2
ここでベクトル同士の積は内積になります
E・E = |E|2 = 1×1 = 1
同じベクトルの内積はベクトルの長さの2乗です
Eは単位ベクトルなので|E|=1です
V・V + 2(V・E)t + t2 = r2 これを変形すると
t2 + 2(V・E)t + (V・V - r2) = 0
tの2次方程式になり、解の公式で
距離t = -V・E±√{ (V・E)2 - V・V + r2 }
となります
判別式D = (V・E)2 - V・V + r2 によって
D < 0 → 交差しない (tは虚数)
D = 0 → 1点で接する(tは1個)
D > 0 → 2点で貫く (tは遠近2個)
の3パターンを判別できます
これをBASICで書いていきます
ベクトルの成分は、
P=(x, y, z)、V=(Vx ,Vy ,Vz)、V=(V0, V1, V2)
などと表しますが、
BASICでは配列を使うことにします
DIM V(2)で、(DIMしないと DIM V(10)になります)
V(0),V(1),V(2)という変数が使えます。
0がx, 1がy, 2がzを意味し
V(0),V(1),V(2)がx,y,z成分です
VとEの内積は、V・E = ViEi = ΣViEi (i=0,1,2)
です。つまり、同じxyz成分同士の積の和です。
b = V・Eは、BASICでは
B = V(0)*E(0) + V(1)*E(1) + V(2)*E(2)
となります
BASICではすべて大文字になり
四則演算は + - * / です
√(n) は、SQR(n)
rの2乗は、r^2 または r*r と書きます
t = -V・E±√( (V・E) - V・V + r2)は、
b = V・E、d = V・V - r2 と置くとt = -b±√(b2 - d)
BASICは行番号(昇順に並ぶ)のあとにプログラムを書きます
BASICは関数をプログラムできませんので、サブルーチンで
代用します。先頭に呼び出すためのラベルを書きます
*から始まる英数字と.の組み合わせです
'はコメントでこれ以降は無視されます
10 *DISTANCE.SPHERE
20 B = V(0)*E(0) + V(1)*E(1) + V(2)*E(2) 'b = V・E
30 D = V(0)*V(0) + V(1)*V(1) + V(2)*V(2) - R*R 'd = V・V - rr
40 D = B*B - D
ここまででDに判別式(√の中身)が入ります
D = B*B - Dは、B×B-Dの計算結果をDに代入するので
元のDの値は上書きされてなくなります
50 IF D < 0 THEN T = -1: RETURN '交点なし
判別式が負のときは交点なしで、見えていない事になります
解tが負のときも、後ろに交点があるのでやはり見えません
よって、見えないときはtを負にして返すことにします
60 D = SQR(D)
70 T = -B - D '視線と球の近い方の交点距離
√の前の±は、-が近いほう、+が遠い方になりますので、
ここまででTに近いほうの交点までの距離が入りました
80 IF T < 0 THEN T = -B + D '視線と球の遠い方の交点距離
近いほうが負ならば交点は後ろで見えないので、遠いほうの
距離をTに入れます
遠い方のTが負なら球は後ろにあります
近い方が負、遠い方が正なら視点が球の中にあります
90 RETURN
これで、呼出し元へ戻ります
ここで、このサブルーチンの呼び出し側では、球の中心が
原点になるよう視点Vを移動させて呼び出されるので、
移動前と区別するため、移動後をV0で表すことにします
呼び出し側でTを使用したいので、TもT0に変えます
サブルーチンの説明をコメントに書いてRENUM 9000で行番号
を付けなおしたプログラムリストをダウンロード出来る
ようにしておきます
プログラムリストはLIST(Enterキー)で表示されます
BASICはEnterキーを押して初めて反応します
プログラムの読込みは
LOAD “ファイル名”(Enterキー)
または、ファイルをNL-BASICの画面に重ねて下さい
NL-BASICとblg~.zip(ray001.bas)は
以下のリンクからダウンロードできます
Readme.txtを読んで遊んで下さい
次回