--shader(GLSL)の小技 17-- twitterに書いた小技のリンク集
小出しだけど、twitterに小技を書いてきた。バラバラになっていたので、まとめてみた。
スムースabs()の作り方。floatをpとした時
— gaz (@gaziya5) May 8, 2019
abs(p)は
p-2.0*min(0.0,p)
と置き換えられる。なので#define smin(a,b,k) -log2(exp2(-k*a)+exp2(-k*b))/k
p-2.0*smin(0.0,p,32.0)
とかで、折り畳みの時の折り目を解消。
ちょっと閃いた。
— gaz (@gaziya5) May 8, 2019
step()をsmoothstep()変えたスムースabs()#define smoothabs(p,k) p-2.0*smoothstep(k,-k,p)*p
折り目が、くびれた感じになる。使えなくもない。 https://t.co/tgRb2f7vPf
twitterに載せれるスムースノイズ。vec2バージョン。
— gaz (@gaziya5) May 7, 2019
float n(vec2 p){
vec2 r=vec2(1,99),s=dot(floor(p),r)+vec2(0,r.y);
p=smoothstep(0.,1.,fract(p));
vec2 a=mix(fract(sin(s)*5555.),fract(sin(s+1.)*5555.),p.x);
return mix(a.x,a.y,p.y);
}
shaderは0~1の範囲のコントロールが基本。これさえ意識していけば、迷子にならずにすむ。この範囲同士の乗算はこの範囲だし、pow()を使ってもこの範囲ですむ。exp()も使いやすいし、出力の色もこの範囲。この範囲以外の数字も出てくるが、それはスケールと思えば問題ない。負数は-1倍と思えばいい。
— gaz (@gaziya5) May 3, 2019
スムースなノイズの考え方は、2つの座標を用意して、その座標をシーズにして乱数を取り、2つの座標の間の補間をsmoothstep()等で滑らかにする事。これをアルゴリズムにしたのが、パーリンノイズ。こらが解って関数を眺めれば、雰囲気がみえてくる。
— gaz (@gaziya5) May 3, 2019
nusanの法線算出
— gaz (@gaziya5) April 30, 2019
vec2 off=vec2(0.01,1);
vec3 n=normalize(map(p)-vec3(map(p-off.xyy),map(p-off.yxy),map(p-off.yyx)));
普段、片側だけ微分するのは嫌ってるけどlive codingは記述速さ優先だから、これは、使ってみようと思う。
hsvの関数の替わりにするならhttps://t.co/ze4bBnYuUY
— gaz (@gaziya5) April 27, 2019
これなら空で書ける。
shader showdownの決勝の一瞬にトンネルのskillがわかりました。@sp4ghet から情報をもらいテストしてみました。https://t.co/qzxLmQuPvH
— gaz (@gaziya5) April 23, 2019
vertex shaderで距離関数からmeshを作ってみた。
— gaz (@gaziya5) April 18, 2019
SurfaceNet test https://t.co/l9tg4Zzrh7 @CodePenさんから
mat3のx,y,z軸用の回転行列を、いちいち作るより、2Dの回転行列一個で処理した方が記述が短くて済みます。
— gaz (@gaziya5) April 12, 2019
mat2 rot=mat2(cos(a), sin(a), -sin(a), cos(a));
p.xy=rot*p.xy;
p.yz=rot*p.yz;
p.zx*=rot*p.zx;
0~1の範囲を-1~1に変えたいときは末尾に
— gaz (@gaziya5) April 12, 2019
*2.0-1.0
-1~1の範囲を0~1に変えたいときは末尾に
*0.5+0.5
2.0*fract(t)-1.0や0.5*sin(t)+0.5
よりfract(t)*2.0-1.0やsin(t)*0.5+0.5の方が慣れると楽です。
レイベクトルrd、レイの原点ro、座標をpとした時、rdとpの距離は
— gaz (@gaziya5) April 12, 2019
length(cross(rd,p-ro))
これで取得できる。これに制限を付けてraymarchigをして負荷軽減。
イメージで言えばバウンディング球みたいな奴。
三角波の応用で3Dビリーヤード状態にオブジェクトを動かすskill。あたかもcompute shaderでも使ってると思わせれる。
— gaz (@gaziya5) April 12, 2019
位置座標をp、移動ベクトルをv、時間をt、範囲をsとした場合。
vec3 p = (abs(fract(v*t)*2.0-1.0)*2.0-1.0)*s;
GPU負荷軽減skill。vertex shaderで複数のbillboardを作りその中でraymarchigして一つの画面に収めるskillがある。似たような事が一枚shaderでも出来る。
— gaz (@gaziya5) April 12, 2019
if(length(cross(rd,p-ro))<2.0){}
カッコのなかに一個のオブジェのmarchig処理を書いて、これを複数作りZソートする。https://t.co/l1bNTcrcyn
p=mod(p,6.0)-3.0;で折り畳んで現れる大量オブジェの間引きskill。各マス目のidをvec3 u=floor(p/6.0);で取得。このuをシーズにして乱数を取得。例えば0.5以上なら距離関数を1.0にして返せば間引き出来ます。ミニ化してるshaderだけど、雰囲気は解ると思います。https://t.co/ZQRaqTVDgm
— gaz (@gaziya5) April 11, 2019
遠くを黒っぽくするtrick。ガウシアンを使う。marching loopで手に入る距離をt、オブジェクトの色をcolとした場合。
— gaz (@gaziya5) April 11, 2019
col*=exp(-0.001*t*t);
この定数は絵を見ながら調整していく。fogというskillだと認識してたけど、もしかして空気遠近法と呼ばれてるかもしれない。使い方次第では、白くも出来る。
クォータニオンに対する反応が意外にあったので、類似で、
— gaz (@gaziya5) April 11, 2019
クォータニオンと同等の回転関数。
vec3 rotate(vec3 p,vec3 axis,float theta){
vec3 v=cross(axis,p),u=cross(v,axis);
return u*cos(theta)+v*sin(theta)+axis*dot(p,axis);
}
最近はクォータニオンを使っていないけど
— gaz (@gaziya5) April 11, 2019
vec4 quaternion(vec3 n, float a){
return vec4(n*sin(a/2.0),cos(a/2.0));
}
vec3 qtransform(vec4 q, vec3 p){
return p+2.0*cross(cross(p,https://t.co/J2rl9Xr9Oj)-q.w*p,https://t.co/J2rl9Xr9Oj);
}
これで出来る。引用元は忘れました。どこだっけ?
初めて知ったけど、palettesと言うトリックは、面白いね。HSVでの色付けに飽きてきたら、試す価値アリです。https://t.co/G4RFCOecmF
— gaz (@gaziya5) February 20, 2019
添削を受けました。https://t.co/rSgJ2kJfz0
— gaz (@gaziya5) 2019年2月18日
float g = (func(p.x+e)-func(p.x-e))/(2.0*e);
は、
float g = (func(p.x+e)-func(p.x-e))/(PI*e);
の方が良好のようです。
このロジックは試行錯誤で偶然見つけたものです。解る方がいましたら理屈を教えてください。さて用意したshaderどうしよう。 https://t.co/FvVaLSsS1A
smoothstepの小技。
— gaz (@gaziya5) February 15, 2019
1.0-smoothstep(a,b,x)
smoothstep(b,a,x)
は、同等。第1引数と第2引数の順番を入れ替えるだけ。
連続値をtimeで増やしていくより、FM音源のスキルを頂いて
— gaz (@gaziya5) February 9, 2019
sin(0.5*time+0.3*sin(0.2*time))
みたいにすると楽しい。フーリエ変換で絵を書いていくのも、こういうスキルの延長なんだよね。きっと。
shaderにストップモーションを入れていると、又、落ちたな。のヒヤヒヤ感が増強される。
— gaz (@gaziya5) February 9, 2019
time=min(8.0, mod(time,9.0));
こんな使い方。
魚眼レンズが素敵。
— gaz (@gaziya5) February 9, 2019
vec3 rd= normalize(vec3(uv,(1.0-dot(uv, uv)*0.5)*0.5));
レイマーチングは単にレイがオブジェクトに衝突するかの判定しかしない。難しいと感じるのは、レイの作り方の説明不足のように思う。shaderのスクリーンをuvに展開してnormalize(vec3(uv,-2)) これがレイだよって言えばいいと思う。後は、カメラの向きを変えたり、色を付けのスキルが、あるだけ。
— gaz (@gaziya5) February 5, 2019
mengerの距離関数の中に出てくる
— gaz (@gaziya5) January 23, 2019
if (p.x<p.y){ p.xy = p.yx;}
は、y=xの直線で折り畳んでいる意味だよね。なんとなくmengerのコーナーの細工を感じる。Shane氏は、これを
p.xy += step(p.x, p.y)*(p.yx - p.xy);
と書いている。shaderならではの書き方だ。
0.5773と丁寧に書いてあるから、深読みしちゃったけど、
— gaz (@gaziya5) January 12, 2019
vec3 calcNormal(vec3 p )
{
vec3 n=vec3(0);
for( int i=ZERO; i<4; i++ )
{
vec3 e=vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-0.5;
n+=e*map(p+e*0.001);
}
return normalize(n);
}
最後normalize()だし、これで問題ないでしょ。
法線算出の面白いコード発見。
— gaz (@gaziya5) January 12, 2019
vec3 calcNormal( in vec3 pos )
{
return normalize( cross(dFdx(pos),dFdy(pos)) );
}
でも、ちょっと粗いです。https://t.co/36doOhwq3U
たぶん、これが最古のtetrahedron normal。
— gaz (@gaziya5) January 11, 2019
四面体で法線算出。https://t.co/FxZ2UH9WhX
2013/02/25だって。知らなかった。
今のshadertoyには、物凄い数のshaderがアップされていて、掘り起こすの大変だぞ。
映像が暗い感じのshaderを一番最後にガンマ補正をかけて、明るくしてもらいたいと思う時がある。
— gaz (@gaziya5) January 8, 2019
col = pow(col, vec3(0.7));
とか。逆に暗くしたければ
col = pow(col, vec3(1.5));
とか。
textureをトンネル風にする小技。inversesqrt()を使います。shadertoyにコピペでどうぞ。
— gaz (@gaziya5) January 8, 2019
vec2 uv=(fragCoord*2.-iResolution.xy)/iResolution.y;
float d=inversesqrt(length(uv));
uv=vec2(d,atan(uv.y,uv.x)/1.57);
vec3 col=(2.-d)*textureLod(iChannel0,uv,0.).xyz;
fragColor=vec4(col,1.);
豆知識。
— gaz (@gaziya5) December 25, 2018
<canvas/ id="canvas" >と書いた後なら、javascriptでcanvas.widthとidが変数名として使えます。
同様に<script id="vs" type="x-shader/x-vertex">...</script>
の中の文字列は、この記述の後ならのjavascriptでvs.textで取り出せます。
shadertoyで録画したwebmをtwitterに載せれるmp4にするコマンド。
— gaz (@gaziya5) December 23, 2018
ffmpeg.exe -i capture.webm -vf fps=30 -pix_fmt yuv420p capture.mp4
豆知識。pow(x,0.5)とsqrt(x)は同等です。
— gaz (@gaziya5) December 22, 2018
豆知識。GLSLのsin()は引数をmod(i,6.283)とかしてません。sin()の引数にtimeとか入れて放置しておくと、おかしなことになってます。pow(-1.0,0.5)とか負数の小数乗は虚数になるようです。GPUによっては、それを無視せずに、それ以前の計算を放棄する奴もいるみたい。注意です。同様に負数のsqrt()もNG
— gaz (@gaziya5) December 22, 2018
ちょっと荒いけど、boxのエッジを取り出す方法。
— gaz (@gaziya5) December 17, 2018
col = vec3(0.8,0.3,0.1)*min(1.0,fwidth(col.x*5.0)*0.5);
こいつでやってます。(webGL2.0用)https://t.co/9MSlhlhdEd
久々に宣伝だ。昔作った、DEエディタ。簡易的に距離関数をつくれる奴。https://t.co/9wVzzbwC5l
— gaz (@gaziya5) December 11, 2018
俺が好んで使っている。2D形状を押出してエッジに丸みをつける距離関数。
— gaz (@gaziya5) December 11, 2018
float map(in vec3 p)
{
float de2D = length(p.xy)-1.0;
float depth = 0.5;
float round =0.2;
return length(max(vec2(de2D, abs(p.z)-depth),0.0))-round;
}
これがあると、2D距離関数が楽しくなるよ。
シーケンスは
— gaz (@gaziya5) December 5, 2018
float Q(float a,float b){
return step(iTime,a+b)*max(0.0,iTime-a);
}
こいつを使いました。world time と local time と言う考え方。
Q(5,10) は開始5秒から0から始まるlocal timeが始まり10秒経過したらlocal timeが0になる。我ながら良いアイデアです。
シーケンスでフラグ制御は
— gaz (@gaziya5) December 5, 2018
e=step(1.0,iTime)
+step(3.0,iTime)
+step(5.0,iTime)*2.0
-step(7.0,iTime);
これです。開始時は0、1秒後に1になり、3秒後に2になり、5秒後に4になり、7秒後に3になる。これで色々と時間管理が出来る。