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

Posted

技术标签:

【中文标题】OpenGL 多重渲染目标 - 黑色输出【英文标题】:OpenGL Multiple Render Target - Black output 【发布时间】:2015-02-27 13:17:04 【问题描述】:

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

结果:

【问题讨论】:

编辑:glCheckError() 没有错误 EDIT2:根据***.com/questions/16757764/…,我的运动纹理的 alpha 通道似乎有问题。如果我禁用 GL_BLEND,我可以看到我的速度纹理:i.imgur.com/Qtdh8VI.png 但是 OpenGL 文档说:“GL_RG:每个元素都是红色/绿色双精度。GL 将其转换为浮点并通过附加 0 将其组装成 RGBA 元素表示蓝色,1 表示 alpha。每个分量都被限制在 [0,1] 范围内。我不明白那里的逻辑。 关于分配 01 的逻辑,这通常是 OpenGL 为纹理和顶点属性扩展向量的方式。它们被视为 4D 向量,缺失的组件使用 0,0,1 分配。如果您只有一个 2D 输入向量,则需要该列表中的最后两个组件使其成为 4D。这允许 2D/3D 向量作为齐次坐标工作并使 RGB 颜色不透明,因此具有良好的行为。 感谢您的解释。我检查了我的运动纹理中的 alpha 通道,它始终是 1,所以它按预期工作。我不明白的是我的运动纹理和 GL_BLEND 模式之间的关系。当 GL_BLEND 被禁用时,我的运动纹理被正确填充,否则它是完全黑色的。 另外,如果我在片段着色器中将 MotionVector 输出为 vec4 而不是 vec2(alpha 值为 1),我不会必须禁用 GL_BLEND 并且正确填充运动纹理。这真的很奇怪。 【参考方案1】:

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

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

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

【讨论】:

这是一个非常有趣的答案。谢谢! 我只是浪费了几个小时试图了解我的着色器出了什么问题。只是禁用 GL_BLEND 就可以了。我永远不会猜到。所以谢谢!

以上是关于OpenGL 多重渲染目标 - 黑色输出的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL4 多重采样抗锯齿和渲染到纹理

OpenGL 3.30 / GLSL 3.30 - MRT 输出黑色纹理

Opengl 透明部分被渲染为黑色

优化流媒体vbo openg

opengl vbo建议[关闭]

OpenGL仅渲染黑色正方形