KeurKeur
KeurKeur

Reputation: 13

Smooth blur gaussian in OpenGL es 2.0

I try to make a smooth gaussian blur but I don't have any idea to how to do it corectly.

I tried a few things like this :

#version 100

precision mediump float;

varying vec3 vColor;
varying vec2 TexCoords;

uniform sampler2D texture0;
uniform float radius;
uniform vec2 dir;
uniform resolution;

void main() {

  vec4 sum = vec4(0.0);

  vec2 tc = TexCoords;

  float blur = radius/resolution;

  float hstep = dir.x;
  float vstep = dir.y;


  sum += texture2D(texture0, vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)) * 0.0162162162;
  sum += texture2D(texture0, vec2(tc.x - 3.0*blur*hstep, tc.y - 3.0*blur*vstep)) * 0.0540540541;
  sum += texture2D(texture0, vec2(tc.x - 2.0*blur*hstep, tc.y - 2.0*blur*vstep)) * 0.1216216216;
  sum += texture2D(texture0, vec2(tc.x - 1.0*blur*hstep, tc.y - 1.0*blur*vstep)) * 0.1945945946;

  sum += texture2D(texture0, vec2(tc.x, tc.y)) * 0.2270270270;

  sum += texture2D(texture0, vec2(tc.x + 1.0*blur*hstep, tc.y + 1.0*blur*vstep)) * 0.1945945946;
  sum += texture2D(texture0, vec2(tc.x + 2.0*blur*hstep, tc.y + 2.0*blur*vstep)) * 0.1216216216;
  sum += texture2D(texture0, vec2(tc.x + 3.0*blur*hstep, tc.y + 3.0*blur*vstep)) * 0.0540540541;
  sum += texture2D(texture0, vec2(tc.x + 4.0*blur*hstep, tc.y + 4.0*blur*vstep)) * 0.0162162162;

  gl_FragColor = vec4(vColor, 1.0) * vec4(sum.rgb, 1.0);
}

But the result is something like that: https://i.sstatic.net/EzqTK.png

How can I achieve a better result?

Upvotes: 1

Views: 1390

Answers (1)

Matic Oblak
Matic Oblak

Reputation: 16794

You seem to be on a correct way but your vstep and hstep seem to be too large. A step should be designed so that just takes a next pixel which means it should be the 1/size where size equals to the texture size in your case.

You do take only a few pixels around which will not produce much of a blur. Usually you would take a 7x7 or 9x9 matrix at least. What you are taking though is a bit strange as this looks like you only use some diagonal values around the current pixel.

In concept the result should be something like

for(horizontalOffset = -radius; horizontalOffset<radius; horizontalOffset  += step) {
    for(verticalOffset = -radius; verticalOffset<radius; verticalOffset += step) {
        sum += texture2D(texture, textureCoordinate+vec2(horizontalOffset, verticalOffset))*gaussFactorForOffset(sqrt(horizontalOffset*horizontalOffset + verticalOffset*verticalOffset)/radius);
    }
}

This is a bit slow though because for instance having 7 steps will produce 49 accesses to the texture which makes it o2. You can optimize it by splitting this into 2 draw calls where in one you create a vertical blur and in the other a horizontal one. This means you need 2 shaders where one takes only a vertical loop and the other one only the horizontal loop. The result is then you have 14 calls to the texture for 7 steps so that makes 2o at the cost of one more draw call and having another texture in memory (unless you can reuse the original one for the second draw call).

Also you may find loads of shaders online on pages such as this one. They are usually not optimized but they may at least get you a place to start at.

Upvotes: 1

Related Questions