这是我第一次尝试使用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矩阵设计为左上角)是原点)),然后我将把这个'第二帧缓冲区'的纹理绘制到它上面。所以对于第二个帧缓冲...这就是我所看到的:
事实上,白盒子(我假设是视锥体)之间存在间隙,让我想知道我是否在错误的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将其作为第二个帧缓冲区的输出:
所以这很好!我似乎正确地在第二个帧缓冲区上绘制四边形。
然后我的问题必须是我没有正确地渲染到默认的帧缓冲区,但我不知道为什么。
为了尝试调试这个,我使用默认的帧缓冲区为着色器做了同样的事情(除了我在片段着色器中做绿色而不是红色)。然而,没有绘制绿色,但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;
}
网格输出:
我不知道我搞砸了。 NDC Z坐标是-0.90还可以吗?如果它们是,则构成四边形的两个三角形到达那里......但它们没有被着色。由于绿色/ alpha在1.0的调试,即使纹理在某种程度上是错误的,那么我应该至少得到一些被绘制的东西。
管道状态很好,交换缓冲区适用于其他事情所以我很确定我没有做错任何事情。没有找到GL错误。
有关为什么三角形没有被默认帧缓冲区拾取的猜测?我只是在默认的帧缓冲区上获得了清晰的颜色,这让我想知道我是否在错误的位置绑定了东西,或者我搞砸了重新绑定默认的帧缓冲区,或者如果我发布的最后一张图片中的NDC坐标是错了,或者如果它是我不知道的其他东西。
在渲染第二遍之前,必须禁用深度测试
glDisable(GL_DEPTH_TEST);
或者必须清除渲染目标(默认帧缓冲区)的深度缓冲区:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
注意,默认情况下,深度函数是GL_LESS
,因此深度测试将失败,如果深度缓冲区未被“清除”,则为1.0。即使深度测试在第1帧成功,在第2帧中颜色缓冲区被清除,深度测试将失败并且根本不渲染。
// Do I need to bind the depth/stencil texture here as well? glBindTexture(GL_TEXTURE_2D, texture);
实际上你根本不应该绑定任何东西。如果将纹理绑定到纹理单元,则可能会创建反馈循环(如果从着色器中对纹理单元进行采样)。如果管道配置不能从中读取,则允许保留渲染目标纹理,但是在“不会渲染”的情况下,最好确保渲染目标纹理不处于“可读”状态时画到。