无法将简单的帧缓冲区渲染到四边形并显示
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。即使深度测试在第一帧成功,在第二帧颜色缓冲区被清除,深度测试将失败并且什么都不渲染。
这是我第一次尝试使用帧缓冲区而不是使用默认帧缓冲区(然后将帧缓冲区纹理绘制到默认帧缓冲区上)。我一路上做错了什么,我不确定是什么。我将列出我正在执行的每个步骤,因为此示例非常接近 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。即使深度测试在第一帧成功,在第二帧颜色缓冲区被清除,深度测试将失败并且什么都不渲染。