🗑️

GLSLで籠目文様

2024/12/06に公開

日本の伝統文様の一つに籠目(かごめ)という竹かごの網目のような文様があります。この記事ではGLSLで籠目文様を実装します。

https://ja.wikipedia.org/wiki/籠目

コードはGLSL Sandbox互換になっています。

precision highp float;

uniform vec2 resolution;

#define PI 3.14159265359

mat2 rotate(float r) {
    float c = cos(r);
    float s = sin(r);
    return mat2(c, s, -s, c);
}

void main(void) {
    vec2 p = gl_FragCoord.xy / min(resolution.x, resolution.y);
    p *= 10.0;

    float w = 0.05;
    float v = 1.0;

    vec2 q1 = p * rotate(-PI / 6.0);
    q1.x = abs(mod(q1.x, 1.0) - 0.5);
    v = mix(0.0, v, step(w, q1.x));

    vec2 q2 = p * rotate(PI / 6.0);
    q2.x = abs(mod(q2.x, 1.0) - 0.5);
    v = mix(0.0, v, step(w, q2.x));

    vec2 q3 = p;
    q3.y = abs(mod(q3.y, 1.0) - 0.5);
    v = mix(0.0, v, step(w, q3.y));

    gl_FragColor = vec4(vec3(v), 1.0);
}

描画結果は以下のようになります。

この実装方法は、以下の図で赤青緑の3色で示したように籠目模様は3方向に一定間隔で線が描かれている模様ということを利用して実装しています。


別の実装です。

籠目模様は赤枠で囲った部分を一単位とした繰り返し模様とみなすことができます。さらに赤枠内を見てると赤い点線で上下左右に対称となっています。

この繰り返しパターンを利用してGLSLで実現すると以下のようになります。

precision highp float;

uniform vec2 resolution;

#define PI 3.14159265359

mat2 rotate(float r) {
    float c = cos(r);
    float s = sin(r);
    return mat2(c, s, -s, c);
}

void main(void) {
    vec2 p = gl_FragCoord.xy / min(resolution.x, resolution.y);
    p *= 10.0;

    p = mod(p, vec2(1.0, sqrt(3.0)));
    p = abs(p - vec2(0.5, 0.5 * sqrt(3.0)));

    float w = 0.05;
    float v = 1.0;

    vec2 q1 = p - vec2(0.5, 0.0);
    q1 = q1 * rotate(PI / 6.0);
    v = mix(0.0, v, step(w, abs(q1.x)));

    vec2 q2 = p;
    q2.y = abs(mod(q2.y, 0.5 * sqrt(3.0)) - 0.25 * sqrt(3.0));
    v = mix(0.0, v, step(w, q2.y));

    gl_FragColor = vec4(vec3(v), 1.0);
}

ここまではフラットなラインの籠目模様でした。
網目のラインが上下に交差するような籠目模様の場合、コードは以下のようになります。

precision highp float;

uniform vec2 resolution;

#define PI 3.14159265359

mat2 rotate(float r) {
    float c = cos(r);
    float s = sin(r);
    return mat2(c, s, -s, c);
}

void main(void) {
    vec2 p = gl_FragCoord.xy / min(resolution.x, resolution.y);
    p *= 10.0;

    p = mod(p, vec2(1.0, sqrt(3.0)));
    p.y -= 0.5 * sqrt(3.0);
    p = p.y > 0.0 ? p : vec2(1.0 - p.x, -p.y);

    float v = 1.0;

    float w1 = 0.06;
    float w2 = 0.1;

    float h = 0.25 * sqrt(3.0);
    v = mix(step(abs(p.y - h), w1), v, p.x > 0.5 ? step(w2, abs(p.y - h)) : 1.0);

    vec2 q1 = p - vec2(1.0, 0.0);
    q1 = q1 * rotate(PI / 6.0);
    v = mix(step(abs(q1.x), w1), v, step(w2, abs(q1.x)));

    vec2 q2 = p * rotate(-PI / 6.0);
    v = mix(step(abs(q2.x), w1), v, step(w2, abs(q2.x)));

    vec2 q3 = p - vec2(1.0, 0.0);
    q3 = q3 * rotate(-PI / 6.0);
    v = mix(step(abs(q3.x), w1), v, step(w2, abs(q3.x)));

    v = mix(step(abs(p.y - h), w1), v, p.x <= 0.5 ? step(w2, abs(p.y - h)) : 1.0);

    gl_FragColor = vec4(vec3(v), 1.0);
}

描画結果は以下のようになります。

2つ目の実装方法と同じように赤枠で囲った部分が繰り返しパターンになってるので、それを利用しています。赤枠内の左右は対称ではありませんが、上下は左右を反転すれば対称となっています。

Discussion