1

I'm currently working on a game project for my school using C++, SFML (for OpenGL context creation, core 3.3), and OpenGL for the rendering part.

Recently, I decided to implement a motion blur. To do this, I need a motion vector for each pixel rendered in my framebuffer object. So in my FBO, i have two texture target :

  • one for the color output
  • one for the motion vector

The color ouput is correctly filled, but the motion vector is always black. I use BuGLe to check the content of my FBO textures.

I know that my issue may come from my texture creation cause I don't understand well all about internal texture format and so on.

Here is my framebuffer creation :

void Framebuffer::create(int sizeX, int sizeY, bool depthBuffer, int repeatMode)
{
    _texture = new GLuint[2];
    std::memset(_texture, 0, sizeof(GLuint) * 2);

    // Create OpenGL framebuffer
    glGenFramebuffersEXT(1, &_fbo);
    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _fbo);

    // Create texture
    glGenTextures(textNbr, _texture);

    for (unsigned int i = 0; i < 2; ++i)
    {
        glBindTexture(GL_TEXTURE_2D, _texture[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, repeatMode);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, repeatMode);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // Color - 4 float components
        if (i == 0)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, sizeX, sizeY, 0, GL_RGBA, GL_FLOAT, NULL);
        // Motion vector - 2 float components
        else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, sizeX, sizeY, 0, GL_RG, GL_FLOAT, NULL);

        // Even if I use "glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sizeX, sizeY, 0, GL_RGBA, GL_FLOAT, NULL);" for both texture, my motion texture is black

        glBindTexture(GL_TEXTURE_2D, 0);
        // getColorAttachment only return GL_COLOR_ATTACHMENTi_EXT
        glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, getColorAttachment(i), GL_TEXTURE_2D, _texture[i], 0);
    }

    // Generate depth buffer
    if (depthBuffer == true)
    {
        glGenRenderbuffersEXT(1, &_depth);
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _depth);
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, sizeX, sizeY);
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
        glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, _depth);
    }

    // Check completion
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
        ogl::error("Can't complete framebuffer creation");

    // Clean
    unbind();
}

Framebuffer binding :

void Framebuffer::bind(void)
{
    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _fbo);

    GLuint *attachment = new GLuint[2];
    for (unsigned int i = 0; i < 2; ++i)
        attachment[i] = getColorAttachment(i);
    glDrawBuffers(2, attachment);
    delete[] attachment;
}

Then my Fragment shader which should write into both texture target at the same time :

#version 330

in vec4 Color0;

layout(location = 0) out vec4 FragmentColor;
layout(location = 1) out vec2 MotionVector;

void main(void)
{
    FragmentColor = Color0;
    MotionVector = vec2(1);
}

Result :

Color texture

Motion texture

  • EDIT : I have no errors from glCheckError() –  Feb 27 '15 at 16:18
  • EDIT2 : According to http://stackoverflow.com/questions/16757764/simple-color-glsl-shader-doesnt-output-anything it seems like something is wrong with the alpha chanel of my motion texture. If I disable GL_BLEND, I can see my velocity texture : http://i.imgur.com/Qtdh8VI.png But the OpenGL documentation says : "GL_RG : Each element is a red/green double. The GL converts it to floating point and assembles it into an RGBA element by attaching 0 for blue, and 1 for alpha. Each component is clamped to the range [0,1]." I don't get the logic there. –  Feb 27 '15 at 16:19
  • Regarding the logic of assigning **0** and **1** that is typically how OpenGL expands vectors for textures and vertex attributes. They are treated as 4D vectors and missing components are assigned using **0,0,1**. If you only have a 2D input vector, it takes the last two components in that list to make it 4D. This allows for 2D/3D vectors to work as homogeneous coordinates and makes RGB colors opaque, so it is good behavior to have. – Andon M. Coleman Feb 27 '15 at 16:40
  • Thanks for the explanation. I checked the alpha channel in my motion texture, it's always **1** so this is working as expected. What I don't understand is the relation between my motion texture and GL_BLEND mode. When GL_BLEND is disabled, my motion texture is filled properly, otherwise it's totally black. –  Feb 27 '15 at 16:57
  • Also, if I output my **MotionVector** as vec4 instead of vec2 in my fragment shader (with alpha value at **1**), I don't have to disable GL_BLEND and the motion texture is filled properly. This is really weird. –  Feb 27 '15 at 17:04
  • I notice that you're not unbinding the 2D textures before attaching them to the framebuffer. As a consequence, you're never unbinding the second attachment from GL_TEXTURE_2D, meaning any number of later calls could be impacting it. Further, if it's never unbound from GL_TEXTURE_2D, I'm not sure it will function as a color destination in the FBO. – Jherico Feb 27 '15 at 23:41
  • I'll edit my code. I tried this but that doesn't solve the problem. I think this is because I unbind the textures after my motion blur pass. Maybe this can be an issue during one frame after the FBO creation. –  Feb 28 '15 at 05:45
  • I would start by using the core entry points for the FBO functionality, instead of their `EXT` version. There's absolutely no need for that, and I could imagine bad interactions between core functions and obsolete extension functions if you call the `EXT` versions. – Reto Koradi Mar 03 '15 at 02:50
  • Thanks for the advice ! I think I used EXT version because I had some issue with the Core version. I'll fix that. –  Mar 04 '15 at 04:23

1 Answers1

3

In the comments, you mentioned that enabling GL_BLEND causes the issue. That is to be expected. Color values outputted by the fragment shader are always 4-component RGBA vectors, no matter what format your framebuffer will have. The following stages of the GL still work with those 4 comoponents. They might just discard them later when writing to the actual frame buffer. If you just declare them as vec2, the other components are just undefined. The expansion to a vec4 of the form (0,0,0,1) is not applied in that case (that is only done when you read from input attributes or textures, so the quote of the GL documentation you braught up in the comments is irrelevant in that case). So the blending works just with an undefined alpha value, which might as well be always 0 by accident.

However, since you just want to blend your real color buffer, I suggest you use glEnablei() instead of glEnable() to just enable blending for the first draw buffer.

Another option would be to use out vec4 and explicitely write 1 to alpha - you still can use a 2 channel framebuffer in that case. Bit the additionall frame buffer read triggered by the unneeded blending for this buffer will still be a performance penalty, so I'd prefer the first option.

derhass
  • 43,833
  • 2
  • 57
  • 78
  • 1
    That was a really interesting answer. Thank you ! –  Mar 03 '15 at 04:03
  • I just wasted hours trying to understand what was wrong with my shaders. Just disabling GL_BLEND did it. I would never have guessed. So thanks! – aslg Mar 01 '16 at 19:32