ぼかし処理の中でも何気によく使われるモザイクを作ってみます。
先の2つと比較すると見えちゃいけないものの処理なんかに使うやつです。
GLSLぼかしシリーズ
モザイクの基本
モザイク処理自体は簡単にできます。
1 2 3 4 5 6 7 8 9 |
precision highp float; //精度 varying vec2 uv; //uv座標 [0-1,0-1] uniform sampler2D t; //テクスチャ uniform vec2 resolution; //解像度 //モザイク数 #define B 20.0 void main(void){ gl_FragColor = texture2D(t, floor(uv*B)/B); } |
モザイク数をB
としてuv
をBxB
に分割しています。
モザイク数を変えてみると画像はこうなります。
式を見てわかるように分割した領域の左下座標の色がサンプリングされます。
この画像を見てもブロック数に関わらず左下は[0, 0]
の色になっています。
ほんの少し改良して領域の中央からサンプリングしてみます。
ブロック左下から領域の半分動かせばいいからこんな感じ。
1 |
gl_FragColor = texture2D(t, floor(uv*B)/B+.5/B); |
まぁ大きな変化はないですね。
処理的にはこちらの方が自然だと思います。
サンプリングをブロック内の平均値にすることなんかも思いつきますが、ループ処理で変数条件が使えないのと処理がめちゃくちゃ増える(最悪で画素数2)ことを考えてやめておきます。
実用モザイク
座標とサイズを指定して円状にモザイクを書ける処理を考えます。
1 2 3 4 5 6 7 8 9 10 11 12 |
#define B 20.0 void mosaicCircle(inout vec4 color, vec2 p,float size){ if(length(uv-p)<size){ color = texture2D(t, floor(uv*B)/B+.5/B); } } void main(void){ vec4 color = texture2D(t, uv); mosaicCircle(color, vec2(.5), .25); mosaicCircle(color, vec2(.75), .1); gl_FragColor = color; } |
同じように任意の長方形にモザイクをかけてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#define B 20.0 void mosaicRect(inout vec4 color, vec2 ps, vec2 pe){ vec2 j = (pe-uv)*(uv-ps); if(j.x*j.y>0.){ color = texture2D(t, floor(uv*B)/B+.5/B); } } void main(void){ vec4 color = texture2D(t, uv); mosaicRect(color, vec2(.5), vec2(.7)); mosaicRect(color, vec2(.3), vec2(.5)); gl_FragColor = color; } |
ps
(左下)とpe
(右上)を指定してモザイクをかけています。
条件式は少し戸惑うかもしれませんが中身は以下のような長方形の中であるかどうかの判定と同じです。
1 |
if(pe.x>uv.x && uv.x>ps.x && pe.y>uv.y && uv.y>ps.y) |
ps<pe
である限り(pe-uv)
と(uv-ps)
が両方マイナスになることはないので乗算した結果がプラスなら範囲の中にあるということになります。
円と組み合わせるとこんな感じ。
1 2 |
mosaicRect(color, vec2(.01), vec2(.99,.25)); mosaicCircle(color, vec2(.5), .25); |
同じように条件を変えていけばどんなモザイクでもかけることが出来ます。
1 2 3 4 5 6 7 |
#define B 5.0 void mosaic(inout vec4 color){ vec2 p = uv*4.-2.; if(p.x*p.x*p.y*p.y*p.y-pow(dot(p, p)-1.,3.)>0.){ color = texture2D(t, floor(uv*B)/B+.5/B); } } |
顔認識なんかと組み合わせると良さそうな気がします。