Fast and beautiful blur filter / shader recommendations?

edited May 2016 in GLSL / Shaders

Hi, I am just working on a project where I need a good looking fast blur effect. Currently I am using Mario Klingemann’s StackBlur – a mixture between a box blur and a gaussian blur. I really like how it looks, the only problem is – it’s lagging a bit on my computer, when using in realtime, see the video here: youtube.com/watch?v=ze65pmIH4i8. Do you know if there is a shader implementation of it or a good alternative?
Thanks,
Cheers Tim

Tagged:

Comments

  • edited July 2014

    Processing comes with a blur example these days!

    Examples > Topics > Shaders > Blurfilter

    If you want to modify the shader, press CTRL+K (or CMD+K if you're one a Mac), in the ./data/ folder you will find a blur.gsl file. Part of that code will look like this:

      // Grouping texcoord variables in order to make it work in the GMA 950. See post #13
      // in this thread:
      // http://www.idevgames.com/forums/thread-3467.html
      vec2 tc0 = vertTexCoord.st + vec2(-texOffset.s, -texOffset.t);
      vec2 tc1 = vertTexCoord.st + vec2(         0.0, -texOffset.t);
      vec2 tc2 = vertTexCoord.st + vec2(+texOffset.s, -texOffset.t);
      vec2 tc3 = vertTexCoord.st + vec2(-texOffset.s,          0.0);
      vec2 tc4 = vertTexCoord.st + vec2(         0.0,          0.0);
      vec2 tc5 = vertTexCoord.st + vec2(+texOffset.s,          0.0);
      vec2 tc6 = vertTexCoord.st + vec2(-texOffset.s, +texOffset.t);
      vec2 tc7 = vertTexCoord.st + vec2(         0.0, +texOffset.t);
      vec2 tc8 = vertTexCoord.st + vec2(+texOffset.s, +texOffset.t);
    
      vec4 col0 = texture2D(texture, tc0);
      vec4 col1 = texture2D(texture, tc1);
      vec4 col2 = texture2D(texture, tc2);
      vec4 col3 = texture2D(texture, tc3);
      vec4 col4 = texture2D(texture, tc4);
      vec4 col5 = texture2D(texture, tc5);
      vec4 col6 = texture2D(texture, tc6);
      vec4 col7 = texture2D(texture, tc7);
      vec4 col8 = texture2D(texture, tc8);
    
      vec4 sum = (1.0 * col0 + 2.0 * col1 + 1.0 * col2 + 
                  2.0 * col3 + 4.0 * col4 + 2.0 * col5 +
                  1.0 * col6 + 2.0 * col7 + 1.0 * col8) / 16.0; 
      gl_FragColor = vec4(sum.rgb, 1.0) * vertColor;
    

    Think you can figure out how to change it to different kernels? Or would you like some help with that too?

  • I use this one (I preferred it over the one that comes with processing but I can't remember why).

    // Adapted from:
    // http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
    
    #ifdef GL_ES
    precision mediump float;
    precision mediump int;
    #endif
    
    #define PROCESSING_TEXTURE_SHADER
    
    uniform sampler2D texture;
    
    // The inverse of the texture dimensions along X and Y
    uniform vec2 texOffset;
    
    varying vec4 vertColor;
    varying vec4 vertTexCoord;
    
    uniform int blurSize;       
    uniform int horizontalPass; // 0 or 1 to indicate vertical or horizontal pass
    uniform float 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 :)
    
    const float pi = 3.14159265;
    
    void main() {  
      float numBlurPixelsPerSide = float(blurSize / 2); 
    
      vec2 blurMultiplyVec = 0 < horizontalPass ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
    
      // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
      vec3 incrementalGaussian;
      incrementalGaussian.x = 1.0 / (sqrt(2.0 * pi) * sigma);
      incrementalGaussian.y = exp(-0.5 / (sigma * 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(texture, vertTexCoord.st) * 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 <= numBlurPixelsPerSide; i++) { 
        avgValue += texture2D(texture, vertTexCoord.st - i * texOffset * 
                              blurMultiplyVec) * incrementalGaussian.x;         
        avgValue += texture2D(texture, vertTexCoord.st + i * texOffset * 
                              blurMultiplyVec) * incrementalGaussian.x;         
        coefficientSum += 2.0 * incrementalGaussian.x;
        incrementalGaussian.xy *= incrementalGaussian.yz;
      }
    
      gl_FragColor = avgValue / coefficientSum;
    }
    

    PDE:

    /**
     * Separate Blur Shader
     * 
     * This blur shader works by applying two successive passes, one horizontal
     * and the other vertical.
     * 
     * Press the mouse to switch between the custom and default shader.
     */
    
    PShader blur;
    PGraphics src;
    PGraphics pass1, pass2;
    PImage img;
    
    void setup() {
      size(640, 360, P2D);
    
      img = loadImage("img.png");
    
      blur = loadShader("blur.glsl");
      //blur.set("blurSize", 9);
      //blur.set("sigma", 5.0f);  
    
      src = createGraphics(width, height, P2D); 
    
      pass1 = createGraphics(width, height, P2D);
      pass1.noSmooth();  
    
      pass2 = createGraphics(width, height, P2D);
      pass2.noSmooth();
    }
    
    void draw() {
    
      blur.set("blurSize", (int)map(mouseX, 0, width, 0, 20));
      blur.set("sigma", map(mouseY, 0, height, 0, 10)); 
    
      src.beginDraw();
      src.background(0);
      src.fill(255);
      src.ellipse(width/2, height/2, 100, 100);
      src.image(img, 0, 0);
      src.endDraw();
    
      // Applying the blur shader along the vertical direction   
      blur.set("horizontalPass", 0);
      pass1.beginDraw();            
      pass1.shader(blur);  
      pass1.image(src, 0, 0);
      pass1.endDraw();
    
      // Applying the blur shader along the horizontal direction      
      blur.set("horizontalPass", 1);
      pass2.beginDraw();            
      pass2.shader(blur);  
      pass2.image(pass1, 0, 0);
      pass2.endDraw();    
    
      image(pass2, 0, 0);
    
      fill(255, 0, 0);
      text(frameRate, 20, 20);
    }
    
    
    void keyPressed() {
     if (key == '9') {
     blur.set("blurSize", 9);
     blur.set("sigma", 5.0);
     } else if (key == '7') {
     blur.set("blurSize", 7);
     blur.set("sigma", 3.0);
     } else if (key == '5') {
     blur.set("blurSize", 5);
     blur.set("sigma", 2.0);  
     } else if (key == '3') {
     blur.set("blurSize", 5);
     blur.set("sigma", 1.0);  
     }  
     } 
    

    Credits go to other people! (Don't know the names).

  • You can also try this one, it's basically the same as posted above, a two pass blur with horizontal and vertical pass (only horizontal shown in the example)

    https://www.shadertoy.com/view/Mtl3Rj

Sign In or Register to comment.