正月休み最終日です。去年はインプットばっかりでなかなか作ることができていなかったので、今年はアウトプットを増やしていきたいと思います
新年一発目の記事は、前々から作れそうだなぁと思っていたモアレをWebGLで実装してみました〜ほんとはWebGLのアドカレに参加したかったんですけど別ので忙しく、間に合いませんでした。。
そもそものきっかけは一昨年のアドカレでdoxasさんが書いていたこれをみて、なるほど、こういうこともできるのか、と思い立ちやってみた次第であります。
モアレとはなにか
モアレまたはモワレ(仏: moiré)は、干渉縞ともいい、規則正しい繰り返し模様を複数重ね合わせた時に、それらの周期のずれにより視覚的に発生する縞模様のことである。
文章だけ見てもなんのこっちゃという感じなので、WebGLモアレ第1弾として目標とした画像をはっつけておきます。

出典:正多面体クラブ
いわゆるパンチングボードというやつを2枚重ねて、ずらしてあげると干渉縞が浮かび上がります。
デモ
ブラウザで見るとこんな感じです。
GitHub Pagesでデモをアップしました。マウスでクリックしながら上下に動かすと、上(手前?)に配置したボードが回転するようになっています。一応スマホでも見れます。
感想
先に言っておきますが、WebGLでやることに特に意味はないですし、実用性もないと思います。画像でよくない!?と言われればそれまで。自己満です
まず、穴あき水玉模様を作らないとなぁと思い、Shadertoyで検索しました。その中から一番シンプルなこちらを参考にさせてもらってます。
そこまで難しくない(自分にとっては難しかった)と思いますが、フラグメントシェーダだけ載せておきます。
precision mediump float;
const float rad = 0.3; //白い円の半径
const ivec2 reps = ivec2(20, 20); //intのvec2 縦横何分割するか(1辺の円の個数/2)
const float angle = 45.0; // 全体の傾き
const float RADIANS = angle * 0.0174532; // 傾きをラジアンにする
mat2 rot = mat2(vec2(cos(RADIANS), -sin(RADIANS)), vec2(sin(RADIANS), cos(RADIANS))); //傾けるための正方行列
uniform vec3 color; //ボードの色
varying vec3 vPos; //座標変換後のポジションを受け取る
void main(){
vec2 p = vPos.xy;
p *= rot; //全体を傾ける
//原点からピクセルの長さを測るときに、距離を0~1にするための処理
vec2 repeat = vec2(fract(p.x * float(reps.x)), fract(p.y * float(reps.y)));
vec2 distFromMid = repeat - vec2(0.5); //中心点を基準にする
float dist = length(distFromMid); //原点からの距離をとる
//半径分移動させて白黒はっきりさせる
float sharpness = 20.0;
float circ = (rad - dist) * sharpness;
float alpha = 1.0 - circ;
gl_FragColor = vec4(color, alpha);
}
同じものを2回レンダリングして重ね、上の面だけマウスイベントでz軸回転させています。
もしかしたら、面を回転させるんじゃなくて、2つの面の間に少しスペース空けて、視点を動かした方がより自然かもしれないな・・・
最初はステンシルバッファを試したくて始めたんですが、意外とめんどくさくて、結局シェーダでやってしまいました。。ステンシルを使ったやり方で作ったよってコメントをお待ちしています
ということで、本年もよろしくお願い致します。