Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm still having some trouble to get my head around fragment shaders and doing some image processing on textures. The context is a 2D sprite: a simple texture painted on a quad. All done with OpenGL ES 2.0.

My very basic goal is a simple blur filter using a 3x3 Kernel with average weights: every pixel used is weighed 1/9th and summed up.

Besides many ways to improve the performance of the fragment shader(code below) so far I'm still having some difficulties to find the right texture coordinate for the kernel.

My approach so far is to use the actual size of the quad on the screen on which the texture is painted and pass those two values to the shader. This is done outside the shader and passed as a uniform to the shader program.

glUniform2f(_offset, 1 / spriteWidth, 1 / spriteHeight);

This should result in the step in both directions to calculate a texture coordinate in the 0 to 1 space.

The result is kind of looking good. BUT I am still struggling if this is something that could be done within the shader. Is there a way to get the size of the texture within the fragment shader? If we would be only doing this on a bitmap, I'll just go from pixel to pixel and read the color of the surrounding pixels. I am wondering if my understanding of a fragment shader is quite right: It's run per rendered pixel on the screen. I found some examples for the GLSL to do this but I wasn't able to port it to OpenGL ES, so I had to start from scratch.

For the sake of readability I write a bit more code in hope it's easier to understand the fragment shader:

varying vec2 v_texCoord;
uniform vec2 u_offset;
uniform sampler2D u_texture;

const int size = 3;
const int KernelSize = size * size;

void main()
{
    int i, j;

    vec4 sum = vec4(0.0);
    vec4 intensityOfPixel;
    vec2 texCoordForKernel;

    for (i = 0; i < size; i++)
    {
        for (j = 0; j < size; j++)
        {
            texCoordForKernel = vec2(v_texCoord.x + (float(i) - 1.0) * u_offset.x,
                                     v_texCoord.y + (float(j) - 1.0) * u_offset.y);

            intensityOfPixel = texture2D(u_texture, texCoordForKernel);

            sum += intensityOfPixel * 1.0 / float(KernelSize);
        }
    }

    gl_FragColor = sum;
}

Thanks alot in advance!

share|improve this question
1  
Isn't that ddx and ddy are used for (might be wrong here)? Otherwise do the 1.0/texturesize in the (c++/ ...) code and set a global uniform shader variable to it. –  Valmond Mar 9 '12 at 12:57
    
@Valmond I don't know what ddx and ddy are but maybe you can give me a hint where to search for those terms related to glsl? Yes that's what I tried to explain how I am doing it right now: The single line of code. I'll clarify that. –  Nick Weaver Mar 9 '12 at 13:03
1  
For little optimization: You don't have to use for (i = 0; ...) and then float(i) - 1, but you can use: for (i = -1; ...) –  zacharmarz Mar 9 '12 at 13:28
    
And if I should comment question: You are doing it right. You have to pass 1/textureWidth and 1/textureHeight. –  zacharmarz Mar 9 '12 at 13:30
    
@zacharmarz Yes there is alot you can refactor and make this more efficient, even go as far as using two different shaders for one axis only. This was just to show my general approach. Thanks for your comment. –  Nick Weaver Mar 9 '12 at 13:42
add comment

1 Answer

up vote 3 down vote accepted

Yes, there is no way for the fragment shader to know what is the size of the bound texture.

Your best approach is to pass the pixel size already calculated instead of the texture bounds, since you are sparing two divisions that would be calculated once per fragment, adding unnecessary overhead.

share|improve this answer
    
Thanks for your answer. I thought I am already passing the divided values already: glUniform2f(_offset, 1 / spriteWidth, 1 / spriteHeight); or are you refering to something else? –  Nick Weaver Mar 9 '12 at 13:40
    
Yes, you are already doing it. I was warning you in case you wanted to change it. –  r2d2rigo Mar 9 '12 at 20:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.