テラByteの時代にキロByte

shader又はdemosceneに関係する事

--shader(GLSL)の小技 06-- raycastをraymarchigに同居させて文字を描く

raycastをraymarchigに同居させて文字を描くことをやってみます。
細かい説明は、そのうちに追記します。何故なら、すっかりアルゴリズムを忘れてました。 raycastはエフェクトに使える可能性があるので、又、取り上げてみます。 shaderの中に文字が出るのはデバックには便利なので用法を載せておきます。

// billboard 関係

vec2 billboard(vec3 ro, vec3 rd, vec3 pos, vec3 nor, vec3 up)
{
    float z = dot(pos-ro,nor)/dot(rd,nor);
    vec3 p=ro+rd*z, a=p-pos, u=normalize(cross(nor,up)),v=normalize(cross(u,nor));
    return vec2(-dot(a,u),dot(a,v));
}

#define POS(a) q = billboard(ro,rd,a,normalize(ro-a),vec3(0,1,0))*5.0;

// Font 
int C[26]=int[](7325,53709,35217,53705,36241,3217,39317,7196,49601,39176,11282,35088,6202,14392,39321,3229,47513,11421,37285,16577,39192,2578,14872,8738,16418,33667);
int N[10]=int[](39835,4106,36237,38285,5148,38293,40341,643,40349,38301);

// ここを変えるとフォントの大きさが変わる。
#define S 2.0
#define P(i)m*vec2(26>>(i)&1,19>>(i)&1)*vec2(0.6,1)*S
float deFont(vec2 p,int n)
{
    float e=10.0;
    mat2 m=mat2(1);
    for(int i=0;i<16;i++){
        if((i&7)==4||i==8)m*=mat2(0,1,-1,0);
        if((n>>i &1) == 1){
            vec2 a=P(i&3),b=P((i&3)+1);
            a.x+=0.3*a.y;
            b.x+=0.3*b.y;
            vec2 c=p-a,d=b-a;
            e=min(e,length(c-d* clamp(dot(c,d)/dot(d,d), 0.1, 0.9)));
        }
    }
    return e;
}

#define NUM(a,c) idx=N[a];de=deFont(q,idx);q.x-=2.0*S;\
    col = mix(c,col,smoothstep(0.1,0.12,de));
#define ALF(a,c) idx=C[a];de=deFont(q,idx);q.x-=2.0*S;\
    col = mix(c,col,smoothstep(0.1,0.12,de));

billboard関係と書いておきましたが、正体はraycastです。とりあえず、コピペで使ってください。当然、読み解いて応用も構いません。
では使い方

    // ここの3つの変数は必須。マクロの中で使ってます。変数が被るなら、上手く調整してください。
    float de;
    vec2 q;
    int idx;
    // POS(文字を書く位置) いわゆるビルボードの中心位置
    POS(vec3(2,1,0))
    // ALF(アルファベットのindex、色) ビルボード上の文字の描写
    ALF(0, vec3(1))
    ALF(1, vec3(1))
    ALF(2, vec3(1))
    POS(vec3(-2,1,0))
    // NUM(数字のindex、色) ビルボード上の文字の描写
    NUM(0, vec3(1,0,0))
    NUM(1, vec3(1,0,0))
    NUM(2, vec3(1,0,0))

あと,ここでフォントの大きさを変えれる。

// ここを変えるとフォントの大きさが変わる。
#define S 2.0

スクリプトを挿入する位置とかは、下を参照してください。

今回のshader (shadertoy rule)

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

float udRoundBox( vec3 p, vec3 b, float r )
{
  return length(max(abs(p)-b,0.0))-r;
}

float map(vec3 p)
{
    p.x=abs(p.x)-2.0;
    return udRoundBox(p,vec3(0.8),0.1);
}

vec3 doColor(vec3 p)
{
    return vec3(0.3,0.5,0.8);
}

// billboard 関係

vec2 billboard(vec3 ro, vec3 rd, vec3 pos, vec3 nor, vec3 up)
{
    float z = dot(pos-ro,nor)/dot(rd,nor);
    vec3 p=ro+rd*z, a=p-pos, u=normalize(cross(nor,up)),v=normalize(cross(u,nor));
    return vec2(-dot(a,u),dot(a,v));
}

#define POS(a) q = billboard(ro,rd,a,normalize(ro-a),vec3(0,1,0))*5.0;


// Font 
int C[26]=int[](7325,53709,35217,53705,36241,3217,39317,7196,49601,39176,11282,35088,6202,14392,39321,3229,47513,11421,37285,16577,39192,2578,14872,8738,16418,33667);
int N[10]=int[](39835,4106,36237,38285,5148,38293,40341,643,40349,38301);

// ここを変えるとフォントの大きさが変わる。
#define S 2.0
#define P(i)m*vec2(26>>(i)&1,19>>(i)&1)*vec2(0.6,1)*S
float deFont(vec2 p,int n)
{
    float e=10.0;
    mat2 m=mat2(1);
    for(int i=0;i<16;i++){
        if((i&7)==4||i==8)m*=mat2(0,1,-1,0);
        if((n>>i &1) == 1){
            vec2 a=P(i&3),b=P((i&3)+1);
            a.x+=0.3*a.y;
            b.x+=0.3*b.y;
            vec2 c=p-a,d=b-a;
            e=min(e,length(c-d* clamp(dot(c,d)/dot(d,d), 0.1, 0.9)));
        }
    }
    return e;
}

#define NUM(a,c) idx=N[a];de=deFont(q,idx);q.x-=2.0*S;\
    col = mix(c,col,smoothstep(0.1,0.12,de));
#define ALF(a,c) idx=C[a];de=deFont(q,idx);q.x-=2.0*S;\
    col = mix(c,col,smoothstep(0.1,0.12,de));

// billboard ここまで

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv=(fragCoord*2.0-iResolution.xy)/iResolution.y;
    vec3 ro=vec3(0,5,-7);
    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;
    }
    
    float de;
    vec2 q;
    int idx;
    // POS(文字を書く位置) いわゆるビルボードの中心位置
    POS(vec3(2,1,0))
    // ALF(アルファベットのindex、色) ビルボード上の文字の描写
    ALF(0, vec3(1))
    ALF(1, vec3(1))
    ALF(2, vec3(1))
    POS(vec3(-2,1,0))
    // NUM(数字のindex、色) ビルボード上の文字の描写
    NUM(0, vec3(1,0,0))
    NUM(1, vec3(1,0,0))
    NUM(2, vec3(1,0,0))
        
    fragColor=vec4(col,1.0);
}