2012.02.13 | 

あと15分で月曜日。今回苦戦のため画像が準備できませんでした。
こんばんはmuchoです。

今回はGLSLでGaussian Blurの自作に挑戦しました。
作りたいというか欲しかったのが、とにかく高速で、大きくボケるフィルター。

ズバリ目指したのはこれ↓
http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
最初はquasimondoさんのソースをさっくり移植しようと思ったんですが、
商用で使ってる方もいるみたいで、二次利用を断念。

こちらのサイトを参考にしました。
http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/
英語なのでいまいちよく分かりませんが、
まず横にぼかしをかけて、
その結果画像をさらに縦にぼかすと
計算が少なくてすむということらしい。
9ピクセルぼかすとすると本来なら
9x9=81
それを横と縦で分けることで
9+9=18
この差は大きい!
実際9x9的な本来のブラーを作ってみましたが、OpenCVのGaussian Blurと比べて
高速化が感じられず、上記の横かけて、縦かけての2段階描画方式にしてみました。
まずはそのままコピペしてみたところ、大きくぼかすとおかしなことに。
というわけで、参考サイトでは9+9固定なのですが、ボカすサイズによって、
描画回数が変わるように書き直してみました。
以下がそのソース。

煮詰まりまくりで作ったので、微妙にソースに意味不明なところがあります。
さらにどうも正弦波の値の求め方がおかしいような?
おまけに、本来のブラーよりは高速化したとはいえ、大きくぼかすと
まだまだ実用には厳しい遅さ。。。
次回はquasimondoさんのソースをさらに読み解きつつ、
これをチューニングできたらと思います。できるのかなー。怪しいなー。

01//horizontal Fragment Shader
02#version 120
03uniform sampler2D texture0;
04uniform int width;
05uniform int height;
06uniform float blurSize;
07 
08void main()
09{
10    float v;
11    float w_step = 1.0 / width;
12    float h_step = 1.0 / height;
13    float radius = blurSize;
14    if ( radius < 0 ) radius = 0;
15    int steps = int(radius);
16    float x = gl_TexCoord[0].x;
17    float y = gl_TexCoord[0].y;
18    float pi = 3.141592653589793;
19    float t = 1/(steps*2+1);
20    vec4 sum = texture2D(texture0, vec2(x, y))*t;
21    int i;
22    for(i = 1; i<=steps;i++){
23        v = (cos(i/(steps+1)*pi)+1)*0.5;
24        sum += texture2D(texture0, vec2(x + i*w_step, y))*v*t;
25        sum += texture2D(texture0, vec2(x - i*w_step, y))*v*t;
26    }
27  
28  gl_FragColor = sum;
29     
30}
31 
32//---------------------------------------------------------------
33//vertical Fragment Shader
34 
35#version 120
36uniform sampler2D texture0;
37uniform int width;
38uniform int height;
39uniform float blurSize;
40 
41void main()
42{
43    float v;
44    float w_step = 1.0 / width;
45    float h_step = 1.0 / height;
46    float radius = blurSize;
47    if ( radius < 0 ) radius = 0;
48    int steps = int(radius);
49    float x = gl_TexCoord[0].x;
50    float y = gl_TexCoord[0].y;
51    float pi = 3.141592653589793;
52    float t = 1/(steps*2+1);
53    vec4 sum = texture2D(texture0, vec2(x, y))*t;
54    int i;
55    for(i = 1; i<=steps;i++){
56        v = (cos(i/(steps+1)/pi)+1)*0.5;
57        sum += texture2D(texture0, vec2(x, y + i*h_step))*v*t;
58        sum += texture2D(texture0, vec2(x, y - i*h_step))*v*t;
59    }
60  
61  gl_FragColor = sum;
62     
63}