Skip to content

Instantly share code, notes, and snippets.

@heisters
Last active July 10, 2020 10:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heisters/22b2e2a95e6ad8cd74b9 to your computer and use it in GitHub Desktop.
Save heisters/22b2e2a95e6ad8cd74b9 to your computer and use it in GitHub Desktop.
Cinder blur filter
uniform float u_sigma; // The sigma value for the gaussian function: higher value means more blur
// A good value for 9x9 is around 3 to 5
// A good value for 7x7 is around 2.5 to 4
// A good value for 5x5 is around 2 to 3.5
// ... play around with this based on what you need :)
// The size of the blur
uniform float u_blurSize;
uniform sampler2D u_tex; // Texture that will be blurred by this shader
// The direction of the blur. vec2(1.0, 0.0) for horizontal, vec2(0.0, 1.0) for
// vertical
uniform vec2 u_direction;
// The inverse of the texture dimensions along X and Y
uniform vec2 u_texcoordOffset;
const float PI = 3.14159265;
void main()
{
vec2 blurMult = u_texcoordOffset * u_direction;
float blurSizePerSide = (u_blurSize - 1.0) * 0.5;
// Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
vec3 incrementalGaussian;
incrementalGaussian.x = 1.0 / (sqrt(2.0 * PI) * u_sigma);
incrementalGaussian.y = exp(-0.5 / (u_sigma * u_sigma));
incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
float coefficientSum = 0.0;
// Take the central sample first...
avgValue += texture2D(u_tex, gl_TexCoord[0].xy) * incrementalGaussian.x;
coefficientSum += incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= blurSizePerSide; i++) {
avgValue += texture2D(u_tex, gl_TexCoord[0].xy - i * blurMult) * incrementalGaussian.x;
avgValue += texture2D(u_tex, gl_TexCoord[0].xy + i * blurMult) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
}
gl_FragColor = avgValue / coefficientSum;
}
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
#include "BlurFilter.h"
#include "Resources.h"
using namespace std;
using namespace ci;
BlurFilter::BlurFilter( int w, int h ) :
mFboA( w, h ),
mFboB( w, h )
{
mBlurShader = gl::GlslProg::create( app::loadResource( RES_BLUR_VERT_SHADER), app::loadResource( RES_BLUR_FRAG_SHADER ) );
}
void BlurFilter::drawTexIntoFBO( gl::Fbo &fbo, const gl::Texture &tex, float sigma, float size, const Vec2f &direction )
{
Vec2f texcoordOffset = Vec2f(1.f, 1.f) / (Vec2f)tex.getSize();
fbo.bindFramebuffer();
mBlurShader->bind();
mBlurShader->uniform("u_sigma", sigma);
mBlurShader->uniform("u_blurSize", size);
mBlurShader->uniform("u_direction", direction);
mBlurShader->uniform("u_texcoordOffset", texcoordOffset);
gl::clear( Color::black() );
gl::setViewport( fbo.getBounds() );
gl::pushMatrices();
gl::setMatricesWindow( fbo.getSize(), false );
gl::draw( tex, fbo.getBounds() );
gl::popMatrices();
mBlurShader->unbind();
mFboA.unbindFramebuffer();
}
ci::gl::Texture
BlurFilter::blur( const ci::gl::Texture &tex, float sigma, float size )
{
auto oldvp = gl::getViewport();
drawTexIntoFBO( mFboA, tex, sigma, size, Vec2f(0.f, 1.f) );
drawTexIntoFBO( mFboB, mFboA.getTexture(), sigma, size, Vec2f(1.f, 0.f) );
gl::setViewport( oldvp );
return mFboB.getTexture();
}
#pragma once
#include "cinder/gl/GlSlProg.h"
#include "cinder/gl/Fbo.h"
class BlurFilter
{
public:
BlurFilter( int w, int h );
ci::gl::Texture blur( const ci::gl::Texture &tex, float sigma, float size );
private:
void drawTexIntoFBO( ci::gl::Fbo &fbo, const ci::gl::Texture &tex, float sigma, float size, const ci::Vec2f &direction );
ci::gl::GlslProgRef mBlurShader;
ci::gl::Fbo mFboA, mFboB;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment