テラByteの時代にキロByte

shader又はdemosceneに関係する事

--shader(GLSL)の小技 05-- 距離関数でバウンディングボックスを使う

raymarchigの進行を高速にする為のバウンディングボックスというtrick。raymarchigはモデルが増えれば増える程、GPUの負荷が増大する。そこで、モデルをグループにしてバウンディングボックスに納めるtrickを作ってみた。モデルが少ない時は邪魔ですが多い時は威力を発揮します。また、モデルを幾つかのグループにするのも有効です。
if (any(greaterThan(abs(p), bb))) return length(max(abs(p)-bb,0.0)) + eps; この部分がそれにあたります。

greaterThan - OpenGL 4 Reference Pages

any - OpenGL 4 Reference Pages

使い方はこんな感じです。

float map(vec3 p)
{
    // この定数は0.01くらいで良いのですが、trickの可視化の為に、この0.0005を用意しました。
    float eps = float[](0.0005, 0.01)[int(step(2.0,mod(iTime,4.0)))];
    // boundingBox
    // rayがbounding box内に進入してない時はboxの距離関数+epsを返す
    vec3 bb =vec3(3.5,3.5,1.5);
    if (any(greaterThan(abs(p), bb))) return length(max(abs(p)-bb,0.0)) + eps;
    // 進入したら細かいパーツ群の距離関数を返す。
    // knotの軌道に30個の球を配置。
    float de = 1.0;
    for (float i=0.; i < 30.; i++)
    {
        float a = i/30.0*radians(360.0); //radians(360.0)はPI*2の代わりに良く使ってます。
        vec3 b =knot(a)-p;
        de = min(de, length(b)-0.5);
    }
    return de;
}

今回のshader (shadertoy rule)

mat2 rotate(float a)
{
    return mat2(cos(a),sin(a),-sin(a),cos(a));
}

vec3 knot(float a)
{
    return vec3(
        sin(a)+2.0*sin(2.0*a),
        cos(a)-2.0*cos(2.0*a),
        -sin(3.0*a)
    );
}

float map(vec3 p)
{
    // この定数は0.01くらいで良いのですが、trickの可視化の為に、この0.0005を用意しました。
    float eps = float[](0.0005, 0.01)[int(step(2.0,mod(iTime,4.0)))];
    // boundingBox
    // rayがbounding box内に進入してない時はboxの距離関数+epsを返す
    vec3 bb =vec3(3.5,3.5,1.5);
    if (any(greaterThan(abs(p), bb))) return length(max(abs(p)-bb,0.0)) + eps;
    // 進入したら細かいパーツ群の距離関数を返す。
    // knotの軌道に30個の球を配置。
    float de = 1.0;
    for (float i=0.; i < 30.; i++)
    {
        float a = i/30.0*radians(360.0); //radians(360.0)はPI*2の代わりに良く使ってます。
        vec3 b =knot(a)-p;
        de = min(de, length(b)-0.5);
    }
    return de;
}

vec3 doColor(vec3 p)
{
    return vec3(0.7,0.3,0.2);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv=(fragCoord*2.0-iResolution.xy)/iResolution.y;
    vec3 ro=vec3(0,3,-12);
    ro.zx*=rotate(iTime*0.5);
    vec3 rd=normalize(vec3(uv,2));
    vec3 w=normalize(-ro);
    vec3 u=normalize(cross(w,vec3(0,1,0)));
    rd=mat3(u,cross(u,w),w)*rd;
    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=doColor(p);
            col*=i*i;
            break;
        }
        p+=rd*d;
    }
    fragColor=vec4(col,1.0);
}