🐟

GLSLでヘリンボーン模様

2024/12/27に公開

ヘリンボーン(herringbone)模様はニシン(herring)などの魚を開いたときの骨(bone)に似ていることから名づけられた四角形を敷き詰めた繰り返し模様です。この記事ではGLSLでヘリンボーン模様を実装します。
https://en.wikipedia.org/wiki/Herringbone_pattern
https://ja.wikipedia.org/wiki/ヘリンボーン_(模様)

ヘリンボーン模様には、長方形を敷き詰めるパターンと長方形ではない平行四辺形を敷き詰めるパターンが存在します。日本の文様としては前者は桧垣文様、後者は杉綾文様に対応します。また、床のフローリングなどのインテリア界隈では前者をヘリンボーン(またはイタリアンヘリンボーン)、後者をフレンチヘリンボーン(またはハンガリアンヘリンボーン)と呼ぶようです。

https://naisouzairyou-annai.jp/pattern/tradition/index.html
https://www.modalina.jp/modapedia/w/e38398e383aae383b3e3839ce383bce383b3/?srsltid=AfmBOopjmqTLK3gHDepluZOsKhx98D7XRy-mRdeGmSGxi_wkQpE11NGg
https://ikuta.co.jp/newscolumn/information/aboutherringbone/
https://www.keope.com/en/magazine/herringbone-floor-tiling


長方形を敷き詰めるパターンのヘリンボーン模様を実装します。
コードはGLSL Sandbox互換になっています。

precision highp float;

uniform vec2 resolution;

#define PI 3.14159265359

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

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

    float aspect = 4.0;

    p *= rotate(-PI / 4.0);
    p.x -= floor(p.y);
    p = vec2(mod(p.x, 2.0 * aspect), mod(p.y, 1.0));
    if (p.x >= aspect) {
        vec2 q = p;
        p.y = mod(q.x, 1.0);
        p.x = (2.0 * aspect - ceil(q.x)) + q.y;
    }

    float w = 0.05;
    float v = step(w, p.x) * step(p.x, aspect - w) * step(w, p.y) * step(p.y, 1.0 - w);

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

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

以前に桧垣文様をGLSLで実装しましたが、このときは長方形の比率を2:1に限定していました。今回の実装も考え方は同じですが、長方形の比率が2:1以外にも対応できるようになっています。

https://zenn.dev/aadebdeb/articles/0e1287f5120855


長方形ではない平行四辺形を敷き詰めるパターンのヘリンボーン模様を実装します。

precision highp float;

uniform vec2 resolution;

#define PI 3.14159265359

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

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

    float aspect = 4.0;
    p.x = abs(mod(p.x, aspect * 2.0) - aspect);
    p.y = mod((p * rotate(PI / 4.0)).y, 1.0);

    float w = 0.05;
    float v = step(w, p.x) * step(p.x, aspect - w) * step(w, p.y) * step(p.y, 1.0 - w);

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

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

平行四辺形を交互に塗り分ける場合は以下のようになります。

precision highp float;

uniform vec2 resolution;

#define PI 3.14159265359

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

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

    float aspect = 4.0;

    vec2 q = p;
    q.x = abs(mod(p.x, aspect * 2.0) - aspect);
    float v = floor(mod((q * rotate(PI / 4.0)).y + floor(p.x / aspect), 2.0));

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

Discussion