无法获得渲染为四边形并显示的简单帧缓冲区

时间:2019-04-01 19:22:55

标签: c++ opengl glsl framebuffer

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

我想要的所有glEnable()状态均已正确设置,根据RenderDoc的说法,这不是一个笨拙的问题。我已经用glDebugMessageCallback注册了一个回调,但没有收到错误。另外,我附加了深度/模板纹理,但在本示例中不使用它(但在解决此问题时将使用它)。

我的代码本质上如下(所有操作都是顺序的,因此如果在步骤X进行了绑定,那么它也将在步骤X + 1进行了绑定):

0)创建用于绘制FBO纹理的VBO / VAO /着色器程序

// This is fine according to RenderDoc

1)使用我们要渲染的纹理和深度/模板纹理创建帧缓冲区:

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,其中正交矩阵被设计为具有左上角是原点)),然后稍后在其上绘制此“第二帧缓冲区”的纹理。所以对于第二个帧缓冲区...这就是我所看到的:

enter image description here

enter image description here

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

如第二幅图所示,四边形本身与之对齐,但是我的一部分想知道我是否对正交矩阵做错了什么……但是,如果NDC Z值为-0.60是可以的,那么我认为转换正在按照我想要的方式进行。

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

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

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

enter image description here

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

然后我的问题必须是我没有正确地渲染到默认的帧缓冲区,但是我不知道为什么。

要尝试调试该问题,我对默认着色器帧缓冲的着色器做了同样的事情(除了我将在片段着色器中使用绿色而不是红色)。但是没有画出绿色,但是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;
    }

网格输出:

enter image description here

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

管道状态很好,交换缓冲区可用于其他事情,所以我很确定自己在这里没有做错任何事情。找不到GL错误。

有人猜测为什么默认的帧缓冲区没有拾取三角形吗?我只是在默认帧缓冲区上获得了清晰的颜色,这让我想知道是在错误的地方绑定东西还是搞砸了重新绑定默认帧缓冲区,还是我发布的最后一张图像中的NDC坐标是是错误的,还是我不知道的其他事情。

2 个答案:

答案 0 :(得分:1)

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

实际上,您根本不应该在此处绑定任何东西。如果将纹理绑定到纹理单元,则可能会创建一个反馈循环(如果从着色器中采样纹理单元)。如果无法从中读取渲染目标纹理,则可以保留渲染目标纹理的边界,但是在“不渲染”的情况下,最好确保渲染目标纹理不在以下情况下处于“可读”状态:绘图。

答案 1 :(得分:1)

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

yourClass

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

glDisable(GL_DEPTH_TEST);

请注意,默认情况下,深度函数为glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ,因此如果未“清除”深度缓冲区,深度测试将失败1.0。即使在第一帧中进行深度测试成功,在第二帧中清除了颜色缓冲区,深度测试也将失败,并且根本不呈现任何内容。

相关问题