无法将简单的帧缓冲区渲染到四边形并显示

Not able to get a simple framebuffer rendered to a quad and displayed

这是我第一次尝试使用帧缓冲区而不是使用默认帧缓冲区(然后将帧缓冲区纹理绘制到默认帧缓冲区上)。我一路上做错了什么,我不确定是什么。我将列出我正在执行的每个步骤,因为此示例非常接近 MCVE。

我想要的所有 glEnable() 状态都已正确设置,根据 RenderDoc,这不是剔除面问题。我已经用 glDebugMessageCallback 注册了一个回调,我没有收到任何错误。我还附加了一个 depth/stencil 纹理,但在这个例子中没有使用它(但在我解决这个问题时会使用它)。

我的代码基本上如下(一切都是顺序的,所以如果在步骤 X 有绑定,那么它也绑定到步骤 X + 1):

0) 创建VBO/VAO/shader绘制FBO纹理的程序

// This is fine according to RenderDoc

1) 使用我们将渲染到的纹理和一个 depth/stencil 纹理创建帧缓冲区:

glGenFramebuffers(1, &fbo);

// Indenting added to this MCVE only
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glBindTexture(GL_TEXTURE_2D, texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

    [same as above but now with a depth24/stencil8 texture]

    assert GL_FRAMEBUFFER_COMPLETE (which returns true)
glBindFramebuffer(GL_FRAMEBUFFER, 0);

2) 渲染阶段,清除默认帧缓冲区

glClearColor(0.1, 0.1, 0.1, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glViewport(0, 0, w, h)

3) 绑定新的FBO并在绘制四边形之前清除它

glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(color/stencil/depth bits)
glViewport(0, 0, w, h)

4) 通过 2 个三角形绘制一个四边形到新的帧缓冲区

// Not needed in the MCVE but will be required in the actual
// application, so I'll put it in here in the odd case this
// is somehow important
glClearDepth(1.0);

// Do I need to bind the depth/stencil texture here as well?
glBindTexture(GL_TEXTURE_2D, texture);
    bind shader program
        set mvp uniform
        bind vbo
            upload 2 triangles to vbo
            // My goal is to draw the quad on the second
            // framebuffer here
            glDrawArrays(...)
        unbind vbo
    unbind shader
glBindTexture(GL_TEXTURE_2D, 0);

5) 将FB纹理绘制到默认帧缓冲区

glBindFramebuffer(GL_FRAMEBUFFER, 0);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
    // QUESTION: Do I also need to bind the depth/stencil here
    //           if I was planning to use it? Right now I do not
    //           and I'm wondering if that's a mistake
    bind second shader program
        create vbo/vao
        bind vbo
            fill up vbo with a quad to draw the framebuffer texture
            glDrawArrays(...)
        unbind vbo
    unbind second shader program
glBindTexture(GL_TEXTURE_2D, 0);

最后一步没有设置制服,因为我给它 NDC 坐标并且不需要转换。

当我 运行 程序和调出帧缓冲区时,我可以看出它正在做 某事 因为我的 FPS 从 4000-5000 fps 下降到大约 2000 fps,我开始收到线圈噪音,当我切换帧缓冲区渲染时,它又回到 4k-5k fps,线圈噪音消失。

然而没有画...

我在 RenderDoc 中打开它以查看发生了什么,这就是它告诉我的内容:

1) 我所有的数据(VBO、视口、清晰的颜色等)都完全符合我的要求。如果您看到的数据有任何错误,那是我对 OpenGL 的误解,而不是代码错误。

2)第二个帧缓冲区和默认帧缓冲区网格结果似乎都在截锥体之外,我做错了吗?

我的第一步是将这些东西绘制到第二个帧缓冲区上(我在 800x600 视口上渲染一个四边形,我想在其中填充上半部分(所以 0,0 到 800,300,其中设计了正交矩阵让左上角作为原点)),然后我会在上面绘制这个 'second framebuffer' 的纹理。所以对于第二个帧缓冲区...这是我看到的:

实际上在白框(我假设是视锥体)之间有一个间隙,这让我想知道我是否在错误的 Z 处绘制了两个逆时针三角形。Renderdoc 说我正在绘制它们在 NDC Z 坐标为 -0.60,所以我认为这是在范围内,因为 NDC 立方体在所有 3 个轴上都是从 -1 到 +1。

四边形本身与第二张图片中看到的一致,但我的一部分想知道我是否以某种方式对我的正交矩阵做错了什么......但是如果 -0.60 的 NDC Z 值是好的,那么我假设转换正在按照我的意愿进行。

RenderDoc 说四边形正在根据帧缓冲区纹理进行渲染,这很好。为了调试它,我做了:

// Force any draw we have to be red and max alpha to debug it
fragColor.x = 1.0;
fragColor.w = 1.0;

根据 RenderDoc,我们将其作为第二个帧缓冲区的输出:

太好了!我似乎在第二个帧缓冲区上正确绘制四边形。

那么我的问题一定是我没有正确渲染到默认帧缓冲区,但我不知道为什么。

为了尝试调试它,我对使用默认帧缓冲区的着色器做了同样的事情(除了我将在片段着色器中使用绿色而不是红色)。然而没有绘制绿色,但 RenderDoc 说我做的其他一切都是正确的。信息如下:

顶点着色器:

    #version 440 core

    layout(location = 0) in vec3 pos;
    layout(location = 1) in vec2 uv;

    out vec2 uvFrag;

    void main() {
        uvFrag = uv;
        gl_Position = vec4(pos, 1.0);
    }

片段着色器:

    #version 440

    in vec2 uvFrag;

    out vec4 fragColor;

    uniform sampler2D framebufferTexture;

    void main() {
        fragColor = texture(framebufferTexture, uvFrag);

        // Debug whether its actually even drawing the quad
        fragColor.y = 1.0;
        fragColor.w = 1.0;
    }

网格输出:

我不确定我哪里搞砸了。 -0.90 的 NDC Z 坐标可以吗?如果是,那么构成四边形的两个三角形就会到达那里……但它们没有被着色。由于使用 green/alpha 在 1.0 进行调试,即使纹理有某种错误,我也应该至少得到 某些东西 被绘制。

管道状态很好,交换缓冲区适用于其他事情,所以我很确定我在那里没有做错任何事。未发现总帐错误。

关于为什么默认帧缓冲区没有拾取三角形的任何猜测?我只在默认帧缓冲区上看到清晰的颜色,这让我想知道我是不是在错误的地方绑定了东西,或者我搞砸了重新绑定默认帧缓冲区,或者我发布的最后一张图片中的 NDC 坐标是否是错了,还是其他我不知道的。

// Do I need to bind the depth/stencil texture here as well?
glBindTexture(GL_TEXTURE_2D, texture);

实际上你根本不应该在那里绑定任何东西。如果将纹理绑定到纹理单元,则可能会创建一个反馈循环(如果纹理单元是从着色器中采样的)。如果管道配置不会从中读取,则允许保留渲染目标纹理边界,但在 "won't render" 的情况下,最好确保渲染目标纹理不处于 "readable" 状态绘图时.

在渲染第 2 遍之前,必须禁用深度测试

glDisable(GL_DEPTH_TEST);

或者必须清除渲染目标的深度缓冲区(默认帧缓冲区):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

注意,默认深度函数是GL_LESS,所以深度测试会失败,如果深度缓冲区不是"cleared",按1.0。即使深度测试在第一帧成功,在第二帧颜色缓冲区被清除,深度测试将失败并且什么都不渲染。