2012.02.16 | mucho
こんにちは。muchoです。
前回のGLSL Gaussian Blur もどき part1に引き続き、GLSLでBlurをかけてみました。
前回、ガウス分布を求める公式がおかしいなーと思いしらべてみたところ
やっぱりおかしかったんですが、ガウス分布はやっぱり正弦波のようなので
結果的には一緒だろうということで、前回と変わらず。
変えたところは、ブラーのサイズによって、計算回数が増えていくんですが、
見た目と速度の具合で、調整しました。
前回とロジックは一緒で
一度横にブラーをかけ、その後、縦のブラーをかけています。
フレームバッファオブジェクトを使ったらかなり高速になりました。
以下抜粋ソースです。なにかの参考になれば。
//----------------------------------------------------- //cpp #include "cinder/app/AppBasic.h" #include "cinder/Capture.h" #include "cinder/gl/Fbo.h" #include "cinder/gl/gl.h" #include "cinder/gl/GlslProg.h" #include "cinder/gl/Texture.h" #include "Resources.h" static const int X_RES = 640; static const int Y_RES = 480; using namespace ci; using namespace ci::app; using namespace std; class GSLS_GaussianBlurApp : public AppBasic { public: void setup(); void update(); void draw(); Color backGround; ColorA drawColor; float mBlurSize; float mBloom; float fps; Capture mCapture; // TEXTURE AND SHADER AND FBO gl::Texture mTexture; gl::Fbo mFbo; gl::GlslProg mShaderH, mShaderV; }; void GSLS_GaussianBlurApp::setup() { backGround = Color(0,0,0); drawColor = ColorA( 1.0f, 1.0f, 1.0f, 1.0f ); try { mCapture = Capture( X_RES, Y_RES ); mCapture.start(); } catch( ... ) { console() << "Failed to initialize capture" << endl; } // SETUP PARAMS mParams = params::InterfaceGl( "params", Vec2i( 200, 85 ) ); mParams.addParam( "FPS", &fps ); mParams.addParam( "BlurSize", &mBlurSize, "min=0.0 max=500.0 step=1.0" ); mParams.addParam( "Bloom", &mBloom, "min=0.0 max=2.0 step=0.01" ); // SETUP SHADER mShaderH = gl::GlslProg( loadResource( RES_VERT_ID ), loadResource( RES_HFRAG_ID ) ); mShaderV = gl::GlslProg( loadResource( RES_VERT_ID ), loadResource( RES_VFRAG_ID ) ); // SETUP FBO gl::Fbo::Format format; mFbo = gl::Fbo( X_RES, Y_RES, format ); // GL setup gl::enableAlphaBlending(); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); gl::clear( backGround, true ); } void GSLS_GaussianBlurApp::update() { if( !mCapture || !mCapture.checkNewFrame()) return; mTexture = mCapture.getSurface(); fps = getAverageFps(); } void GSLS_GaussianBlurApp::draw() { gl::clear( backGround, true ); if(!mTexture) return; // // テクスチャーから横ブラーをFBOへドロー gl::pushMatrices(); gl::setMatricesWindow(X_RES, Y_RES, false); mFbo.bindFramebuffer(); gl::clear( backGround, true ); mTexture.bind( 0 ); mShaderH.bind(); mShaderH.uniform( "texture0", 0 ); mShaderH.uniform( "width", X_RES ); mShaderH.uniform( "blurSize", mBlurSize ); mShaderH.uniform( "bloom", mBloom ); gl::drawSolidRect( getWindowBounds() ); gl::popMatrices(); mShaderH.unbind(); mTexture.unbind(); mFbo.unbindFramebuffer(); gl::popModelView(); // // FBOから縦ブラーをシーンにドロー gl::pushModelView(); mFbo.bindTexture(0); mShaderV.bind(); mShaderV.uniform( "texture0", 0 ); mShaderV.uniform( "height", Y_RES ); mShaderV.uniform( "blurSize", mBlurSize ); mShaderV.uniform( "bloom", mBloom ); gl::drawSolidRect( getWindowBounds() ); mShaderV.unbind(); mFbo.unbindTexture(); gl::popModelView(); }
//----------------------------------------------------- // Vertex Shader void main() { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform(); }
//----------------------------------------------------- // Fragment Shader horizontal #version 120 uniform sampler2D texture0; uniform int width; uniform float blurSize; uniform float bloom; void main() { float v; float pi = 3.141592653589793; float e_step = 1.0 / width; float radius = blurSize; if ( radius < 0 ) radius = 0; int steps = int(min(radius * 0.7, sqrt(radius) * pi)); float r = radius / steps; float t = bloom / (steps * 2 + 1); float x = gl_TexCoord[0].x; float y = gl_TexCoord[0].y; vec4 sum = texture2D(texture0, vec2(x, y)) * t; int i; for(i = 1; i <= steps; i++){ v = (cos(i / (steps + 1) / pi) + 1) * 0.5; sum += texture2D(texture0, vec2(x + i * e_step * r, y)) * v * t; sum += texture2D(texture0, vec2(x - i * e_step * r, y)) * v * t; } gl_FragColor = sum; }
//----------------------------------------------------- // vertical Shader horizontal #version 120 uniform sampler2D texture0; uniform int height; uniform float blurSize; uniform float bloom; void main() { float v; float pi = 3.141592653589793; float e_step = 1.0 / height; float radius = blurSize; if ( radius < 0 ) radius = 0; int steps = int(min(radius * 0.7, sqrt(radius) * pi)); float r = radius / steps; float t = bloom / (steps * 2 + 1); float x = gl_TexCoord[0].x; float y = gl_TexCoord[0].y; vec4 sum = texture2D(texture0, vec2(x, y)) * t; int i; for(i = 1; i <= steps; i++){ v = (cos(i / (steps + 1) / pi) + 1) * 0.5; sum += texture2D(texture0, vec2(x, y + i * e_step * r)) * v * t; sum += texture2D(texture0, vec2(x, y - i * e_step * r)) * v * t; } gl_FragColor = sum; }
個人的には100ピクセルぼかして60fps出せたので大満足!