こんにちは。muchoです。
前回のGLSL Gaussian Blur もどき part1に引き続き、GLSLでBlurをかけてみました。
前回、ガウス分布を求める公式がおかしいなーと思いしらべてみたところ
やっぱりおかしかったんですが、ガウス分布はやっぱり正弦波のようなので
結果的には一緒だろうということで、前回と変わらず。
変えたところは、ブラーのサイズによって、計算回数が増えていくんですが、
見た目と速度の具合で、調整しました。
ブラーサイズ50pxで60fps
ブラーサイズ100pxで60fps
ブラーサイズ300pxだと40fpsを切ってしまった。
前回とロジックは一緒で
一度横にブラーをかけ、その後、縦のブラーをかけています。
フレームバッファオブジェクトを使ったらかなり高速になりました。
以下抜粋ソースです。なにかの参考になれば。
//-----------------------------------------------------
//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出せたので大満足!