HTMLでレイトレーシング (4回目)

2021/6/12(土)

HTMLでレイトレーシング (4)

 

by ULproject for HTML(JavaScript, canvas)

 

参考記事

N88-BASICでレイトレーシング (4回目)

 

今回は陰影(濃淡)を付けます

 







濃淡は表面の色を表す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)は

以下のリンクからダウンロードできます

VL-BASIC(N88-BASIC互換?)ホームページ

Readme.txtを読んで遊んで下さい


VL-BASICホームページのHTML項目内で

htmlの動作を見ることが出来ます

https://vlbasic.amebaownd.com/pages/3605089/page_202002222051


 次回

HTMLでレイトレーシング (5回目)


このブログの人気の投稿

NEWS

N88-BASICでゲーム (1回目)