OpenGL 多渲染目标 - 黑色输出

OpenGL Multiple Render Target - Black output

我目前正在为我的学校开发一个游戏项目,使用 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);
}

结果:

在评论中,您提到启用 GL_BLEND 会导致问题。这是可以预料的。片段着色器输出的颜色值始终是 4 分量 RGBA 向量,无论您的帧缓冲区采用何种格式。 GL 的以下阶段仍然适用于这 4 个组件。他们可能会在写入实际帧缓冲区时丢弃它们。如果你只是将它们声明为 vec2,其他组件只是 undefined。扩展到 (0,0,0,1) 形式的 vec4 是 not 在这种情况下应用(只有当你 read 来自输入属性或纹理,因此在这种情况下,您在评论中提到的 GL 文档的引用是无关紧要的)。因此,混合仅适用于未定义的 alpha 值,该值也可能意外地始终为 0。

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

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