OpenGL多重渲染目标 - 黑色输出

时间:2015-02-27 13:17:05

标签: opengl glsl framebuffer

我目前正在为我的学校开发一个游戏项目,使用C ++,SFML(用于OpenGL上下文创建,核心3.3)和OpenGL用于渲染部分。

最近,我决定实施动态模糊。为此,我需要为我的帧缓冲对象中渲染的每个像素提供一个运动矢量。所以在我的FBO中,我有两个纹理目标:

  • 一个用于颜色输出
  • 一个用于运动矢量

正确填充了颜色输出,但运动矢量始终为黑色。我使用BuGLe来检查我的FBO纹理的内容。

我知道我的问题可能来自我的纹理创建因为我不太了解内部纹理格式等等。

这是我的帧缓冲区创建:

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();
}

帧缓冲绑定:

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;
}

然后我的片段着色器应该同时写入两个纹理目标:

#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);
}

结果:

Color texture

Motion texture

1 个答案:

答案 0 :(得分:3)

在评论中,您提到启用GL_BLEND会导致问题。这是可以预料的。片段着色器输出的颜色值总是4分量RGBA向量,无论帧缓冲器具有什么格式。 GL的以下阶段仍然适用于这4个组成部分。他们可能稍后在写入实际帧缓冲区时丢弃它们。如果您只是将它们声明为vec2,则其他组件只是 undefined 。在这种情况下,扩展为表单(0,0,0,1)的vec4是而不是(仅当您从输入属性或纹理读取时才会执行此操作,所以你在评论中提到的GL文档的引用与那种情况无关)。因此,混合仅使用未定义的alpha值,也可能偶然为0。

但是,由于您只想混合真实的颜色缓冲区,我建议您使用glEnablei()而不是glEnable()来启用第一个绘制缓冲区的混合。

另一种选择是使用out vec4并明确地将1写入alpha - 在这种情况下你仍然可以使用2通道帧缓冲​​。将由此缓冲区的不需要的混合触发的附加帧缓冲区读取位仍然是性能损失,因此我更喜欢第一个选项。