Pages

Monday, 7 December 2015

A simple box blur implementation in OpenGL/ES using shaders

Here I am going to share one of the simplest approach to apply blur. This is not an optimized solution. For an optimized solution you can go for multi-pass rendering and (or) down sampling.
In this approach bluring will be done by taking average color value around a rectangular are of the pixel. Most of this operation will be performed in the fragment shader. This is a single pass algorithm.

Vertex Shader

As we are doing most of the operation in the fragment shader, vertex shader will be very straight forward.

// Vertex coordinate
attribute vec4 aPosition;

// Texture coordinate
attribute vec2 aTexCoordinate;

// Texture coordinate to be passed to fragment shader
varying  vec2 vTexCoordinate;

void main() {
    vTexCoordinate = aTexCoordinate;
    gl_Position = aPosition;
}

Fragment Shader

precision mediump float;

// The sampler object
uniform sampler2D uSampler;

// Texture coordinate passed from vertex shader
varying  vec2 vTexCoordinate;

// This is the value that needs to be added(subtracted) to a 
// texture point to get the next(previous) pixel in the X direction
// This value can be calculated as 1/texturewidth
uniform float uXPixelDistance;

// This is the value that needs to be added(subtracted) to a
// texture point to get the next(previous) pixel in the Y direction
// This value can be calculated as 1/textureheight
uniform float uYPixelDistance;

// How to jump to next pixel, 1 means the very next pixel,
// 2 means the 2th pixel, and so on.
const float jump = 2.0f;

// Number of points around the current point
const float pointRange = 10.0f;

void main() {
    vec4 color = vec4(0, 0, 0, 0);
    vec2 point;
    int count = 0;
 
    // Calculate the total color intensity around the pixel
    // In this case we are calculating pixel intensity around 10 pixels
    for(float u = -pointRange; u < pointRange ; u+=jump) {
        for(float v = -pointRange ; v < pointRange ; v+=jump) {
            point.x = vTexCoordinate.x  + u * uXPixelDistance;
            point.y = vTexCoordinate.y  + v * uYPixelDistance;
            
            // If the point is within the range[0, 1]
            if (point.y >= 0.0f && point.x >= 0.0f &&
                point.y <= 1.0f && point.x <= 1.0f ) {
                ++count;
                color += texture2D(uSampler, point.xy);
            }
        }
    }
    
    // Take the average intensity for the region
    color = color / float(count);
 
    gl_FragColor = vec4(color.xyz, 1.0f);
}

No comments:

Post a Comment