のぐそんブログ

暗いおじさんがシコシコ書くブログです。

フラグメントシェーダーでグリッチをやりたいけど上手くいかない

グリッチ(glitch)ぽい表現

フラグメントシェーダーを利用して、デジタル表現でよくあるグリッチに挑戦したいと思います。

理想は↓です。ただし私ではこの完成度は無理ですが、まずは挑戦してみます。 https://codepen.io/ykob/pen/GmEzoQ

ランダムなラインをつくる

まずはランダムなラインを作ります。

ホワイトノイズを利用してランダムな線を作成します。

precision mediump float;
varying vec2 vUv;
uniform sampler2D uTex;
uniform float uTime;

//ノイズ生成関数
float random (vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

void main(){

     float r = random(vec2(u.y * .001)); 
     
     gl_FragColor = vec4(vec3(r),1.0);

}

下記のような絵ができます。

ランダムなラインを動かす

作成したランダムなラインを動かします。 mod関数にuTime(経過時間)を渡しているのは、uTimeをそのまま使うと、徐々にラインの幅が大きくなってしまったので、3.0以上にならないようにしました。

precision mediump float;
varying vec2 vUv;
uniform sampler2D uTex;
uniform float uTime;

//ノイズ生成関数
float random (vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

void main(){

     float r = random(vec2(u.y * .001, mod(uTime,3.))); 

     
     gl_FragColor = vec4(vec3(r),1.0);

}

UV座標にノイズを加える

最終的にはテクスチャにノイズを加えたいので、UV座標にこれまでに作成いたラインのノイズを適応します。

precision mediump float;
varying vec2 vUv;
uniform sampler2D uTex;
uniform float uTime;

float random (vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

void main(){
    vec2 u = vUv;
    
    //ノイズを作成
    float r = random(vec2(u.y * .001, mod(uTime,3.))); 
    if (r < 0.1) {
        u.x += r * .1;
    }

    gl_FragColor = texture2D(uTex, u); 
}

色をずらす

グリッチ感をだすにはRGBの座標をノイズに合わせてずらすと良さそうです。

precision mediump float;
varying vec2 vUv;
uniform sampler2D uTex;
uniform float uTime;

float random (vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

void main(){
    vec2 u = vUv;
    
    //ノイズを作成
    float r = random(vec2(u.y * .001, mod(uTime,5.))); 
    if (r < 0.1) {
        u.x += r * .1;
    }

    if (r < 0.1) {
        gl_FragColor.r += texture2D(uTex, u  + vec2(.01, 0.)).b; 
        gl_FragColor.b += texture2D(uTex, u  - vec2(.01, 0.)).g; 
    }else{
         gl_FragColor = texture2D(uTex, u); 
    }
    
}

少し調整する

ノイズの感じとかを少し調整します。

precision mediump float;
varying vec2 vUv;
uniform sampler2D uTex;
uniform float uTime;

float random (vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

void main(){

    vec2 u = vUv;
    
    //ノイズを作成
    float r = random(vec2(u.y * .001, mod(uTime * 20.,20.))); 
    if (r < 0.1) {
        u.x += r * .1;
    }

    if (r < 0.1) {
        gl_FragColor.r += texture2D(uTex, u + vec2(.01, 0.)).b; 
        gl_FragColor.b += texture2D(uTex, u - vec2(.01, 0.)).g; 
    }
    else if(r > 0.2 && r < 0.205){
         gl_FragColor = texture2D(uTex, u + vec2(0., 0.2));
    }
    else{
         gl_FragColor = texture2D(uTex, u);
    }
}

まとめ

最終的にはこんな感じになりました。

なんかイマイチです。

参考

ほとんど↓のコードを参考にさせてもらいました。 勿論、vedaのサンプルファイルの方がはるかにかっこいいです。 https://github.com/fand/veda