--shader(GLSL)の小技 02-- オブジェクトの回転
基本shaderは、リアルタイムなので、動きが欲しくなります。なので、移動より回転を先にしたくなります。
なので、今回は回転について。
3Dの回転なので、mat3の行列が必要と思われがちですが、2Dで回転させた方が、おすすめです。
mat3だと、xyz各軸用の行列を用意しなければならないが、mat2の回転行列を1つだけ持ちxy平面、yz平面、zx平面を回した方が楽に記述できます。
任意軸回転だとmat3は欲しくなるけど、2Dでオイラー回しができるので、普通に使うのには、不自由しないと思います。
今回boxの距離関数を用意したけど、説明は、又の機会にします。
mat2(cos(a),sin(a),-sin(a),cos(a));
これが2Dの回転行列になります。
何故こうなるかについては
qiita.com
こちらを見てください。
ここでは、使い方の説明をします。
単純です。xy平面を回転させたければ,rotate()をかける(*=)だけ。続いて違う平面を回転すれば、オイラー回しになります。
p.xy*=rotate(iTime);
ここで補足です。 このやり方は正しくはありません。正式には
p.xy=rotate(iTime)*p.xy;
です。上のやり方はp.xy
に逆行列をかけていることになります。でも回転なので、反対に回るだけなので気にしないで使ってるだけです。
上のやり方を書き直すと
p.xy=p.xy*rotate(iTime);
逆行列も使う機会もあると思うので、認識だけはしておいた方が良いと思います。
今回のshaderはro(視点)の位置を少し後ろにしました。
// 前回 vec3 ro=vec3(0,0,-3); // 今回 vec3 ro=vec3(0,0,-5);
こんな事ですけど、仕組みを理解してないと、わからない事ですから一応書いておきました。
今回のshader (shadertoy rule)
mat2 rotate(float a) { return mat2(cos(a),sin(a),-sin(a),cos(a)); } float deBox(vec3 p) { return length(max(abs(p)-vec3(1),0.0)); } float map(vec3 p) { p.xy*=rotate(iTime); p.yz*=rotate(iTime); return deBox(p); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv=(fragCoord*2.0-iResolution.xy)/iResolution.y; vec3 ro=vec3(0,0,-5); vec3 rd=normalize(vec3(uv,2)); float d,i,t=0.0; vec3 p=ro; vec3 col=vec3(0); for(i=1.0;i>0.0;i-=1./50.0) { t+=d=map(p); if(d<0.001) { col+=i*i; break; } p+=rd*d; } fragColor=vec4(col,1.0); }