🔸
GLSLでsnub squareタイリング
この記事では半正則タイリングの一つで、正四角形と正三角形を用いて平面を埋めるsnub squareタイリングをGLSLで実装します。
コードは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 *= 8.0;
// mirror symmmetry
vec2 q = mod(p, 1.0);
q.x = mod(p.x, 2.0) < 1.0 ? q.x : 1.0 - q.x;
q.y = mod(p.y, 2.0) < 1.0 ? q.y : 1.0 - q.y;
q = 2.0 * (mod(q, 1.0) - 0.5);
p = q;
float d = 2.0 / (1.0 + sqrt(3.0));
float w = 0.05; // border weight
float b = 0.8; // border blur rate
q *= rotate(PI / 6.0);
q = abs(q);
float v = q.x < d && q.y < d ? 0.2 : 0.4; // fill color of square and triangle
// border of square
v = mix(v, 1.0, 1.0 - smoothstep(b * w, w, abs(q.x - d)) * smoothstep(b * w, w, abs(q.y - d)));
// rotational symmetry
q = p;
float s = 0.5 * PI;
float a = atan(q.y, q.x);
a = floor(a / s) * s;
q *= rotate(a);
// border of triangle
v = mix(v, 1.0, (1.0 - smoothstep(b * w, w, abs(q.y - 1.0))) * step(1.0 - d, q.x));
gl_FragColor = vec4(vec3(v), 1.0);
}
描画結果は以下のようになります。
snub squareタイリングは以下の図を正方格子上に並べた繰り返しパターンになっています。この図は赤線で区切ったように上下左右に鏡面対称になっています。さらに赤線で区切られた中の一つに着目してみると、緑の線で区切ったように90度の回転対称になっています。そのため、GLSLでの実装においては座標を変換することで緑の線で囲まれた箇所のみだけを考えればいいことになります。上記の実装では、実装の容易さから正三角形間の境界となる線の描画のみ回転対称を利用しています。
コード中の具体的な値の計算は以下のようになっています。
参考
Discussion