テラByteの時代にキロByte

shader又はdemosceneに関係する事

--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);
}