【GLSL】いろいろ実験してみた【GIF画像付き】

253, 2019-11-24

目次

はじめに

最近のWebGLやOpenGLではシェーダーを書くのが一般的で、GLSLという言語でシェーダーを書きます。
GLSLはC言語に似た文法を持っている言語で、頂点や色に対してきめ細かく処理することが出来ます。
今回はGLSLを使っていくつかサンプルを作り、その動作風景をGIF画像にしてみました。
GLSLのコードもそのまま掲載しているので、もし気になった動作があれば参考にして頂ければ幸いです。

ユーティリティ

↓のようなツールを用意していますが、これは以降のコードには記述していません。

脳内補完お願いします

void swap(inout float a, inout float b) {
    float tmp = a;
    a = b;
    b = tmp;
}

void swap(inout vec3 a, inout vec3 b) {
    vec3 tmp = a;
    a = b;
    b = tmp;
}

ぴょんぴょん

ぴょんぴょん

ボックスが飛び跳ねているように見えるシェーダーです。なかなかかわいらしいですね。意外にこれは好評でした。

// vertex shader
attribute float frame;
attribute vec4 position;
uniform mat4 mvpMatrix;

void main(void) {
    position.x += cos(frame/100.0);
    position.y += sin(frame/10.0);
    gl_Position = mvpMatrix * position;
}
// fragment shader
void main(void) {
}

次の方どうぞ

次の方どうぞ

三角形が列を作って突っ込んでいくスクリプトです。
ちなみにこれは普通のWebGLです。

// my.js

// models
var x;
var y;
var rad = my.math.to_radians(_frame);

x = Math.tan(_frame/100);
y = Math.sin(_frame/50);

_model_a.identity();
_model_a.scale([0.5, 0.5, 0.5]);
_model_a.translate([x, y, 0]);
_model_a.rotate(rad * 10, [0, 0, 1]);

x = Math.tan(_frame/250);
y = Math.sin(_frame/50);

_model_b.identity();
_model_b.translate([x, y, 0]);
_model_b.scale([1.5, 1.5+y/3, 1.5]);

回転灯?

回転灯

パトカーの回転灯のように発光しながら回転する三角形です。
ドキッとしたあなたはいさぎよく出頭しましょう。

// vertex shader
attribute vec3 position;
attribute vec4 color;
uniform mat4 mvp_matrix;
uniform float frame;
varying vec4 v_color;
varying float v_frame;

void main(void) {
    vec3 pos = position;  // copy

    float rad = radians(frame * 12.0);
    float s = sin(rad);
    float c = cos(rad);
    pos[0] = c * pos[0] + pos[0] * s;
    // pos[0] = c * pos[0] + pos[0] * s * s;  // reverse

    gl_Position = mvp_matrix * vec4(pos, 1.0);

    v_color = color;
    v_frame = frame;
}
// fragment shader
precision mediump float;
varying vec4 v_color;  // not used
varying float v_frame;

void main(void) {
    // vec4 clr = v_color;  // copy
    float r = max(0.7, abs(sin(radians(v_frame) * 4.0)));

    gl_FragColor = vec4(r, 0.2, 0.1, 1.0);
}

箱6*4

箱の群れ

並んでいる箱が適当に動き回るスクリプトとシェーダ―です。
うねうねしていて気持ち悪い動きですね。

// my.js
...
        // models
        var offs_x = -3.0;
        var offs_y = -2.0;
        var x = 0.0;
        var y = 0.0;
        for (var i = 0; i < _boxs.length; ++i) {
          var obj = _boxs[i];
          var z = 0.0;
          obj.move([offs_x + x, offs_y + y, z]);
          obj.update(_pv_matrix);
          if (x >= 6-1) {
            y += 1.0;
            x = 0.0;
          } else {
            x += 1.0;
          }
        }
...
// vertex shader
attribute vec3 position;
attribute vec4 color;
uniform vec2 texutre_coord;
uniform mat4 mvp_matrix;
uniform float frame;
varying vec4 v_color;
varying float v_frame;
varying float v_flag;


void main(void) {
    vec3 pos = position;  // copy
    float rad = radians(frame * 4.0);
    float s = sin(rad / 10.0);
    float c = cos(rad / 10.0);

    pos[0] = max(pos[0], c * pos[0] + s);
    pos[1] = max(pos[1], s * pos[1] + c);
    pos[2] = pos[2] + s / 20.0;

    float cnt = mod(frame, 300.0);
    float flag = 0.0;
    if (cnt < 150.0) {
        float tmp = pos[0];
        pos[0] = pos[2];
        pos[2] = tmp;
        flag = 1.0;
    } else if (cnt > 200.0) {
        flag = 2.0;
    }

    gl_Position = mvp_matrix * vec4(pos, 1.0);
    v_color = color;
    v_frame = frame;
    v_flag = flag;
}
// fragment shader
precision mediump float;

varying vec4 v_color;
varying float v_frame;
varying float v_flag;

void main(void) {
    vec4 clr = v_color;  // copy
    float rad = radians(v_frame);
    float r = 0.2;
    float cnt = mod(v_frame, 1000.0);

    if (cnt < 400.0) {
        r = 0.5;
    } else if (cnt > 800.0) {
        r = 0.7;
    } else {
        r = 0.4;
    }

    if (v_flag == 0.0) {
        clr[3] = max(0.3, clr[3] + sin(rad));
    } else {
        clr[3] = max(0.5, clr[3] + cos(rad));
    }

    clr[0] = r;
    clr[1] = (clr[2] + clr[0]) / 2.0;
    clr[2] = (clr[2] + clr[1]) / 2.0;
    gl_FragColor = clr;
}

反復横飛び

反復横跳び

テクスチャを貼った四角形が左右、上下などいろいろな方向に反復横跳びするシェーダーです。
これはJavaScriptでも記述できると思います。

// vertex shader
attribute vec3 position;
attribute vec4 color;
attribute vec2 texture_coord;
uniform mat4 mvp_matrix;
uniform float frame;
varying vec4 v_color;
varying float v_frame;
varying vec2 v_texture_coord;

void main(void) {
    vec3 pos = position;  // copy
    vec4 red = vec4(1.0, 0.0, 0.0, 1.0);
    vec4 purple = vec4(1.0, 0.0, 1.0, 1.0);
    vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);
    vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);

    float rad = radians(frame);
    float s = abs(sin(rad));
    float c = abs(cos(rad));
    float sep = 180.0;
    float nrange = mod(frame, sep*5.0);

    if (nrange < sep) {
        pos[0] += c - s;
        pos[1] += c * s;
        v_color = red;
    } else if (nrange < sep*2.0) {
        pos[0] += c * s;
        pos[1] += c - s;
        v_color = purple;
    } else if (nrange < sep*3.0) {
        pos[0] += c - s;
        pos[1] += c - s;
        pos[2] += c * s;
        v_color = blue;
    } else if (nrange < sep*4.0) {
        pos[0] += c - s;
        pos[1] += s - c;
        pos[2] += c * s;
        v_color = yellow;
    } else {
        pos[1] += c * s;
        pos[2] += c - s;
        v_color = color;
    }

    gl_Position = mvp_matrix * vec4(pos, 1.0);

    v_frame = frame;
    v_texture_coord = texture_coord;
}
// fragment shader
precision mediump float;

uniform sampler2D texture;
varying vec4 v_color;
varying float v_frame;
varying vec2 v_texture_coord;

void main(void) {
    vec4 clr = v_color;  // copy
    vec4 smp_color = texture2D(texture, v_texture_coord);
    gl_FragColor = clr * smp_color;
}

拍手をしながら回る

拍手をしながら回る

拍手をしているように見えるボックスが回転するシェーダーです。
じっさいには拍手のような軌道ではなく、回転した軌道なのですが、見方次第ですね。

// vertex shader
attribute vec3 position;
attribute vec4 color;
attribute float frame;
uniform mat4 mvpMatrix;
varying vec4 vColor;
varying float vFrame;

void main(void) {
    vFrame = frame;
    vColor = color;

    vec3 pos = position; // Copy

    // Move on circle
    vec2 org = vec2(0.0, 0.0); // Origin of move
    float r = 1.0; // Radius
    float speed = 2.0; // Speed of move

    float cx = org.x + r * cos(radians(frame) * speed);
    float cy = org.y + r * sin(radians(frame) * speed);

    // Rotate by axis Y
    float rad = radians(frame) * speed*4.0;
    float rs = sin(rad);
    float rc = cos(rad);
    float rx = rc * pos.x + rs * pos.z;

    // Update position
    pos.x = rx + cx;
    pos.y += cy;

    // Done
    gl_Position = mvpMatrix * vec4(pos, 1.0);
    gl_PointSize = 20.0;
}
// fragment shader
precision mediump float;
varying vec4 vColor;
varying float vFrame;

void main(void) {
    vec4 color = vColor;
    color[0] = cos(radians(vFrame)/4.0);
    color[1] = sin(radians(vFrame)/4.0);
    gl_FragColor = color;
}

うねうね

うねうね

うねうねしていてこれぞシェーダー! というようなシェーダーです。

// vertex shader
attribute vec3 position;

void main(void) {
    gl_Position = vec4(position, 1.0);
}
// fragment shader
precision mediump float;
uniform float frame;
uniform vec2 resolution;
uniform vec2 mouse;

void main(void) {
    vec2 m = vec2(mouse.x * 2.0 - 1.0, -mouse.y * 2.0 + 1.0);
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
    float t = sin(length(cos(m + p*4.0)) * frame/40.0);
    gl_FragColor = vec4(vec3(max(p.x, 0.6), t, max(p.y, 0.2)), 1.0);
}

縦模様

縞模様になるだけのシェーダーです。
これは画像なしでどうぞ。
想像してください。
想像力が鍛えられるシェーダーです。

// vertex shader
attribute vec3 position;

void main(void) {
    gl_Position = vec4(position, 1.0);
}
// fragment shader
precision mediump float;

void main(void) {
    vec2 c = gl_FragCoord.xy;
    gl_FragColor = vec4(abs(sin(c.x) * 4.0), 0.0, 0.0, 1.0);
}

参照

投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク