PDA

View Full Version : How to blur an image?



Ehsan Kamrani
01-01-2011, 09:33 AM
I have applied used this blur shader:


[vert]
#version 130
uniform float radius_x, radius_y; // typycally radius_x = 1.0 / (texture resolution x)

void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0 - vec4(-radius_x, 0.0, 0.0, 0.0);
gl_TexCoord[1] = gl_MultiTexCoord0 - vec4(radius_x, 0.0, 0.0, 0.0);
gl_TexCoord[2] = gl_MultiTexCoord0 - vec4(0.0, -radius_y, 0.0, 0.0);
gl_TexCoord[3] = gl_MultiTexCoord0 - vec4(0.0, radius_y, 0.0, 0.0);

gl_Position = ftransform();
}

[frag]
#version 130
uniform sampler2D tex_unit_0; // texture from previous blurring stage

void main()
{
vec4 sample[4];

sample[0] = texture2D(tex_unit_0, gl_TexCoord[0].st);
sample[1] = texture2D(tex_unit_0, gl_TexCoord[1].st);
sample[2] = texture2D(tex_unit_0, gl_TexCoord[2].st);
sample[3] = texture2D(tex_unit_0, gl_TexCoord[3].st);

gl_FragColor = (sample[0] + sample[1] + sample[2] + sample[3]) / 4.0;
}



and have used the following code to use this shader:



glUniform1f(glGetUniformLocation( g_render.m_blurProgram , "radius_x"), 1.5/textureSize );
glUniform1f(glGetUniformLocation( g_render.m_blurProgram , "radius_y"), 1.5/textureSize );
glUniform1i(glGetUniformLocation( g_render.m_blurProgram , "tex_unit_0"), 0 );
glUseProgram( g_render.m_blurProgram );

glClearColor( 0,0,0,0 );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
gluOrtho2D(0, 1, 0, 1 );
glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
glPushAttrib( GL_VIEWPORT_BIT | GL_CURRENT_BIT );
glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );

glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(0, 0 );
glTexCoord2i(1, 0); glVertex2i(1, 0 );
glTexCoord2i(1, 1); glVertex2i(1, 1 );
glTexCoord2i(0, 1); glVertex2i(0, 1 );
glEnd();
glEnable( GL_LIGHTING );
glFlush();
glUseProgram(0);

glActiveTexture( GL_TEXTURE0 );
glDisable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, 0);

glEnable( GL_CULL_FACE );

glPopAttrib();
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glPopMatrix();

But the shader doesn't change my texture at all. What's the problem?

kRogue
01-01-2011, 11:14 AM
Your blur shader is just taking the average of the 4 nearest pixels, keep this in mind. Some questions:

what is the resolution of your texture? what is the resolution you are displaying the texture at? what are the texture filter modes of the texture, i.e. what are GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER set to?

If you poke into the texturing chapters of the GL specification, you will see how the answer to each of those affect what is returned by the texture2D calls, moreover following the expressions will yield why under certain circumstances it looks like the answer is the same.

Right now, your blur shader all it does is average a box...it is not a "real" blur shader. Typically, a blur takes more than just a 2x2 box into account, and it also is not just a simple average. A good keyword to google: "Gaussian filter separable".

Ehsan Kamrani
01-01-2011, 11:54 AM
Actually I want to use this texture for glow effect. So its dimensions are 512 * 512.
Both of the values for GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER are GL_LINEAR.
However nothing changes at all. This shader must blur the texture a bit. am I correct? So why it doesn't work?
If I make sure that this shader works fine, then I can repeat it for N times.

V-man
01-01-2011, 12:15 PM
For one thing, you are calling glUniform1f before calling glUseProgram.

http://www.opengl.org/wiki/GLSL_:_common_mistakes#glUniform_doesn.27t_work

Dark Photon
01-01-2011, 12:21 PM
However nothing changes at all. This shader must blur the texture a bit. am I correct? So why it doesn't work?
Suggest you write and post a short GLUT test program that illustrates your problem so folks can try locally and advise.

The code you've posted doesn't show where you're binding the texture to blur to texture unit 0. It also doesn't show how you're setting up the render target, and establishing that the result is identical to the original texture. A short test program would answer all these questions, and you'd probably find your bug in the process.

Ehsan Kamrani
01-01-2011, 12:48 PM
Here's my code:


if ( g_menu.m_useShader && g_render.UsingShader() && g_render.m_useShader )
glUseProgram( g_render.m_blurProgram );
glUniform1i(glGetUniformLocation( g_render.m_blurProgram , "radius_x"), 1.5/textureSize );
glUniform1i(glGetUniformLocation( g_render.m_blurProgram , "radius_y"), 1.5/textureSize );
glUniform1i(glGetUniformLocation( g_render.m_blurProgram , "tex_unit_0"), 0 );

if ( g_render.UsingFBOs() && g_render.m_useFBOs )
g_render.BindFBO(m_fboID2);
glClearColor( 0,0,0,0 );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
glOrtho(0, 1, 0, 1, 0.01, 100);
glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
glPushAttrib( GL_VIEWPORT_BIT | GL_CURRENT_BIT );
glViewport( 0, 0, textureSize, textureSize);
glActiveTexture( GL_TEXTURE0 );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_bloomTexture );
glColor3f( 0.0f, 0.0f, 1.0 );
glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex3d(0, 0, -1);
glTexCoord2i(1, 0); glVertex3d(1, 0, -1);
glTexCoord2i(1, 1); glVertex3d(1, 1, -1);
glTexCoord2i(0, 1); glVertex3d(0, 1, -1);
glEnd();
glEnable( GL_LIGHTING );
glFlush();

if ( g_render.UsingFBOs() && g_render.m_useFBOs )
{
g_render.BindFBO(0);
}
if ( g_menu.m_useShader && g_render.UsingShader() && g_render.m_useShader )
glUseProgram(0);
glEnable( GL_CULL_FACE );
glPopAttrib();
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glPopMatrix();


So I use a FBO and bind the shader to render the data to the texture of FBO. If I change the parameters in my shader( for example if I change the final value of gl_fragColor ) it changes the result.So my shader workds. but the shader doesn't blur the texture at all.
In the above code, I want to blur the m_bloomTexture. So how is it possible?

Alfonse Reinheart
01-01-2011, 12:59 PM
I don't see anything there where you're binding your FBO. Or just building it.

However, if "m_bloomTexture" is part of your FBO, then that will never work. You cannot simultaneously read from and write to the same texture. You can write to a different texture, which is the double-buffering scheme that was mentioned in the thread you cited and ignored.

Ehsan Kamrani
01-01-2011, 01:16 PM
Well, m_bloomTetxure refers to m_fboID. Here I have bound m_fboID2. So I'm not simultaneously read from and write to the texture.

Ehsan Kamrani
01-01-2011, 01:41 PM
Are u sure that this shader blurs the texture?

Ehsan Kamrani
01-01-2011, 03:11 PM
I'm wondering why my blur shader acts like a very simple texture. If I change it to:


[vert]
#version 110
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}

[frag]
#version 110
uniform sampler2D tex_unit_0;

void main()
{
gl_FragColor = texture2D(tex_unit_0, gl_TexCoord[0].st);
}

Then I get the same result! So why the blur texture doesn't work? I'm sure that my shader has been loaded successfully and works.

Ehsan Kamrani
01-01-2011, 07:34 PM
MY PROBLEM SOLVED :)
as V-Man said, the problem was about sending the data. now I have blurred the image for 5 times and added it to the scene using additive blending. but the scene is bright.
How can I decrease the brightness of the blurred texture?

kRogue
01-01-2011, 11:58 PM
Set you blend coefficient to 1/#times, you can do this via glBlendFunc together with setting the "constant" blend color with glBlendColor. Beware of banding.