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

问题描述 投票:2回答:2

这是我第一次尝试使用framebuffers而不是使用默认的(然后将帧缓冲纹理绘制到默认的帧缓冲区)。我一路上做错了,我不确定是什么。我将列出我正在做的每一步,因为这个例子非常接近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到800,300,其中ortho矩阵设计为左上角)是原点)),然后我将把这个'第二帧缓冲区'的纹理绘制到它上面。所以对于第二个帧缓冲...这就是我所看到的:

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还可以吗?如果它们是,则构成四边形的两个三角形到达那里......但它们没有被着色。由于绿色/ alpha在1.0的调试,即使纹理在某种程度上是错误的,那么我应该至少得到一些被绘制的东西。

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

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

c++ opengl glsl framebuffer
2个回答
1
投票

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

glDisable(GL_DEPTH_TEST);

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

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

注意,默认情况下,深度函数是GL_LESS,因此深度测试将失败,如果深度缓冲区未被“清除”,则为1.0。即使深度测试在第1帧成功,在第2帧中颜色缓冲区被清除,深度测试将失败并且根本不渲染。


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

实际上你根本不应该绑定任何东西。如果将纹理绑定到纹理单元,则可能会创建反馈循环(如果从着色器中对纹理单元进行采样)。如果管道配置不能从中读取,则允许保留渲染目标纹理,但是在“不会渲染”的情况下,最好确保渲染目标纹理不处于“可读”状态时画到。

© www.soinside.com 2019 - 2024. All rights reserved.