HTMLでレイトレーシング (4回目)
2021/6/12(土)
HTMLでレイトレーシング (4回目)
by ULproject for HTML(JavaScript, canvas)
参考記事
今回は陰影(濃淡)を付けます
濃淡は表面の色を表すdiffuse(拡散反射係数)
を使用します
RGB各0~1で指定し、0~1の実数で濃淡を表現
します
RGB各256階調で表現するための変換をしています
前回のx0,y0,ix,iy,izの値を使用して
色c、濃淡b、大きさiz×izの点を
(ix × iz + x0 , iy × iz + y0)
のPC画面座標に描く関数
function draws(CL, x0, y0, ix, iy, iz)
{
var c, i;
if (CL[3] < 0.0) return;
c = '#';
i = Math.floor(CL[0]*255);
if (i > 255) i = 255; else if (i < 0) i = 0;
c += ('00' + i.toString(16)).substr(-2); // R
i = Math.floor(CL[1]*255);
if (i > 255) i = 255; else if (i < 0) i = 0;
c += ('00' + i.toString(16)).substr(-2); // G
i = Math.floor(CL[2]*255);
if (i > 255) i = 255; else if (i < 0) i = 0;
c += ('00' + i.toString(16)).substr(-2); // B
linebf(ix*iz + x0, iy*iz + y0, iz, iz, c);
}
Math.floorは小数点以下切捨て
i.toString(16)は16進数の文字列に変換し
('00' + i.toString(16)).substr(-2)
で、右から2文字を取り出しています
最終的に'#rrggbb'の16進数に変換しています
光が球面に垂直に当たった場所は明る
く、水平方向から当たった場所は暗く
見え、その光は乱反射(四方八方に拡散)
しますので、球をどの方向から見ても
光の量は変わりません
つまり、視線Eの方向は無関係ということです
この光を拡散光(diffuse)と言い次式で表わします
b = L・N
見ている球の中心が原点になるように
変換した座標系で考えると、
P:視線が見ている球表面上の点
N:点Pでの球の法線ベクトル(N = P/|P|)
球の表面の接面に垂直な単位ベクトル
L:点Pから光源を見る方向
図2
bは図2のLの矢印の先からNに
下した垂線との交点と点Pの距離で、
θが0°で最大の1、90°で0となり、
この値は、球表面に当たる単位面積
当たりの光の量に比例します
光が当たっていない場所の明るさを
環境光で指定します(Amで定義)
0番の球を減衰しない点光源にし、視線と球の
交点の色cと明るさbを求める関数
function shade(_CL, V, E)
{
var _t = new Array(1);
var V0 = new Array(3);
var P = new Array(3);
var N = new Array(3);
var t, si, b;
si = distance(_t, V, E);
t = _t[0];
if (t < 0) { _CL[3] = -1; return; }
_CL[0] = SD[si][0]; _CL[1] = SD[si][1]; _CL[2] = SD[si][2];
_CL[3] = 1;
if (si == 0) return; // light
V0[0] = V[0] - SP[si][0];
V0[1] = V[1] - SP[si][1];
V0[2] = V[2] - SP[si][2];
P[0] = V0[0] + E[0] * t;
P[1] = V0[1] + E[1] * t;
P[2] = V0[2] + E[2] * t;
b = Math.sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);// P = V0+Et
if (b != 0) b = 1/b; else b = 0;
N[0] = P[0] * b;
N[1] = P[1] * b;
N[2] = P[2] * b; // N = P/|P|
P[0] = SP[0][0] - (P[0] + SP[si][0]);
P[1] = SP[0][1] - (P[1] + SP[si][1]);
P[2] = SP[0][2] - (P[2] + SP[si][2]);
b = Math.sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);
if (b != 0) b = 1/b; else b = 0;
P[0] *= b;
P[1] *= b;
P[2] *= b; // P = L(光源方向)
b = P[0]*N[0] + P[1]*N[1] + P[2]*N[2]; // b = L・N
if (b < Am) b = Am; // ambient
_CL[0] *= b; _CL[1] *= b; _CL[2] *= b;
}
を作ります
siが交点のある球の番号ですので、
si=0の球は光源にしたので濃淡なしにします
V0[0] = V[0] - SP[si][0];
V0[1] = V[1] - SP[si][1];
V0[2] = V[2] - SP[si][2];
P[0] = V0[0] + E[0] * t;
P[1] = V0[1] + E[1] * t;
P[2] = V0[2] + E[2] * t;
V0を球を原点にした時のVとして、
P = V0 + Etで、原点にある球上の
点の座標Pを求めます
b = Math.sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);// P = V0+Et
if (b != 0) b = 1/b; else b = 0;
N[0] = P[0] * b;
N[1] = P[1] * b;
N[2] = P[2] * b; // N = P/|P|
法線ベクトルN = P/|P| を|P|=0のときエラーに
ならないように工夫して求めます
P[0] = SP[0][0] - (P[0] + SP[si][0]);
P[1] = SP[0][1] - (P[1] + SP[si][1]);
P[2] = SP[0][2] - (P[2] + SP[si][2]);
b = Math.sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);
if (b != 0) b = 1/b; else b = 0;
P[0] *= b;
P[1] *= b;
P[2] *= b; // P = L(光源方向)
点Pから光源方向の単位ベクトルL
を求めます。Pはもう使わないので
Lの値はPに入れています
b = P[0]*N[0] + P[1]*N[1] + P[2]*N[2]; // b = L・N
if (b < Am) b = Am; // ambient
b = L・Nを求めます
bが環境光Am未満ならbを環境光
にします
_CL[0] *= b; _CL[1] *= b; _CL[2] *= b;
で明るさを反映させます
CL[0~2]に表示色(RGB)が入ります
CL[3] < 0の時は交点なしです
ray004.htmlはMicrosoft Edgeに重ねると
動き、メモ帳でコードを見ることが出来ます
blg~.zip(ray004.html)は
以下のリンクからダウンロードできます
Readme.txtを読んで遊んで下さい
VL-BASICホームページのHTML項目内で
htmlの動作を見ることが出来ます
https://vlbasic.amebaownd.com/pages/3605089/page_202002222051
次回