軽率にRaymarchingを写経した

最近シェーダープログラムのお勉強をしているのですが

ということなのでいい機会だからやってみることにしました

写経するのはこちらのシェーダープログラム

UnityのUnlitシェーダーで軽率にRaymarchingを始めるハンズオン

まだ途中ですが以下わからんところ
1-1.とりあえずピンクにしてみる

 
fixed4 frag(v2f_img i) : SV_Target
 {

 }
わかる

1-2.とりあえず黒にしてみる
 fixed4 frag(v2f_img i) : SV_Target
 {
 	fixed4 col = (0).xxxx;
 	
 	return col;
 }
(0).xxxx 何この書式・・・

1-3.板ポリを3次元っぽく扱えるようにしてみる
 fixed4 frag(v2f_img i) : SV_Target
 {
 	fixed4 col = (0).xxxx;
 	float2 uv = 2 * i.uv - 1;
 	float3 p = float3(uv, 0);
 	
 	return col;
 }
 
xy座標を-1~1の間に正規化してるっぽいことはわかる。
pが3次元での座標を表す変数ということだろうか?

1-4.ここから先はしばらく絵に変化がなくて寂しいのでなんか背景を描いてみる
 fixed4 frag(v2f_img i) : SV_Target
 {
 	fixed4 col = (1).xxxx;
 	float2 uv = 2 * i.uv - 1;
 	float3 p = float3(uv, 0);
 	
 	col.rg = uv;
 	col.b = dot(uv, uv);
 	return col;
 }
dotわからん・・・内積がなんなのかわからん・・・

1-5.動きが欲しいので背景を動かしてみる
uv = 2 * i.uv - 1 + frac(_Time.y);
frac(_Time.y)で時間の小数部を取得するので
座標が斜めに動く→元の位置にワープを
1秒間隔で繰り返す。はず。

1-6.後で使うかもしれない関数を書き足す
 float2 rot(float2 p, float a) {
 	return float2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a));
 }
 
 float mod(float x, float y) {
 	return x - floor(x / y) * y;
 }
rot なぜこの式で回転する・・・?
mod modは除算の余りを返す関数、実際にx=7,y=3で計算すると1が返る。

1-7.途中経過
 	// 背景
 	uv = rot(uv, _Time.y);
 	uv += sin(_Time.y);
 	col.rg = uv;
 	col.b = pow(1 - dot(uv, uv), 0.4);
 	return col;
背景がうごいた・・・!
dotの部分はぜんぜんわからん・・・

2-1.カメラを置く
  float2 uv = 2 * i.uv - 1;
  float3 p = float3(uv, 0);
  
  // カメラ
  float3 cam = float3(0, 0, -3);
原点(0,0,0)から -3 z方向に動いた場所にカメラを置いたっぽいことはわかる

2-2.3つの軸を作る
 float3 cam = float3(0, 0, -3);
 
 // 上、前、横
 float3 up = float3(0,1,0);
 float3 fwd = normalize(-cam);
 float3 side = normalize(cross(up, fwd));
upはわかる
fwdはカメラの向きとは逆のベクトル?を作ろうとしてる?normalizeは0~1に正規化する?
side cross??外積??横向きのベクトルを求めようとしているんだと思うけどcrossが何なのかわからん・・・

2-3.レイの初期座標を決める
float3 rayPos = cam;`
わかる

2-4.レイが進む向きを決める
float3 rayDir = p.x * side + p.y * up + fwd`
平面上(最初に置いた板ポリ)の向こう側に空間があると想定して
板ポリ上の座標(p.x, p.y)の位置が決まるとレイの向きも決まるということ???

2-5. map関数を作って球を描けるようにしてみる
 float map(float3 p) {
 	float s = length(p - (1).xxx);
 	return s;
 }
これ知ってる!進研ゼミで習った距離関数ってやつだ!

2-6.レイマーチするループを作る
 for(int j=0; j<16; j++) {
 	float d = map(p);
 	if(d < 0.0001) break;
 	rayPos += d * rayDir;
 }
レイの位置がオブジェクトとどれだけ離れているか(d)を取得して
一定の距離以下ならばループを抜ける、そうでなければレイの先端からdの距離分だけレイを進める。だっけ?

2-7.mapの結果を使って白で書いてみる
 if(d < 0.0001) {
 	return (1).xxxx;
 }
距離が一定以下(オブジェクトと衝突)したら白を返すということですね。わかります。

3-1.動かしてみる
 float map(float3 p) {
 	float3 q = p;
 	q.xy += sin(_Time.y + UNITY_PI / 2);
 	return dSphere(q);
 }
PI / 2を足してる理由は背景の青い円と動きをずらすためっぽい?

3-2.立体感を出すために法線を使ってみる
 float3 normal(float3 p) {
 	float EPSILON = 0.0001;
 	return normalize(float3(
 		map(float3(p.x + EPSILON, p.y, p.z)) - map(float3(p.x - EPSILON, p.y, p.z)),
 		map(float3(p.x, p.y + EPSILON, p.z)) - map(float3(p.x, p.y - EPSILON, p.z)),
 		map(float3(p.x, p.y, p.z  + EPSILON)) - map(float3(p.x, p.y, p.z - EPSILON))
 	));
 }
EPSILONとは・・・?なぜあの式で法線が算出できるのか・・・?

3-3.ライトの位置と色を決めてみる
float3 L = normalize(float3(-1, -1, 1));`
float3 Lcol = float3(0.9, 0.7, 0.4);`
normalizeでライトの位置(向き)を0~1に正規化
Lcolは単純に色を指定している
ここでエラーになる原因に関してはdotが返すのはfloat型の値だからだということを教えてもらいました。 サンキュー!

3-4.ライトと法線の角度を元にライティングしてみる
 if (d < 0.0001) {
 	float3 L = normalize(float3(-1.0, 0.5, -0.2));
 	float3 Lcol = float3(2.6, 2.3, 1.4);
 	return fixed4(dot(L, N) * 0.5 + 0.5, 1); // Half Lambert
 }
returnの行でエラーになる。どうして・・・?


3-5.そこはかとなくいじっておしまい
float2 uv2 = uv + 0.5 * sin(_Time.y) + 0.5;
uv2.x += sin(floor(4 * uv2.y) - _Time.y);
uv2.x += cos(floor(4 * uv2.x) + _Time.y);
uv2の座標にfloorを使うことで座標を升目状に区切ってるっぽい?

後半の法線が出てきたあたりからは完全についていけなくなったのと内積、外積がほんとにわからんので その辺をちょっとは勉強する必要がありそうだなー。と思いました。まる。

TOP

コメントする

メールアドレスが公開されることはありません。

CAPTCHA