从一个帧缓冲区读取到另一个帧缓冲区时出现问题

Posted

技术标签:

【中文标题】从一个帧缓冲区读取到另一个帧缓冲区时出现问题【英文标题】:Trouble reading from one frame buffer to another 【发布时间】:2015-09-08 01:16:17 【问题描述】:

我已经尝试在我的引擎中实现延迟着色/渲染有一段时间了,但是我还没有真正看到它的最终产品。

为了测试问题可能出在哪里,我设计了一个实验,以查看我的目标 FBO 是否真的通过 glBlitFramebuffer() 命令从我的默认 FBO 中读取。

我已经做到了,在我的默认 FBO 自行清除之前,透明颜色设置为 黑色,在我的目标 FBO 自行清除之前,透明颜色设置为 红色。

结果是当我渲染我的场景时,我看到的都是黑色。

我的问题是这样的:

如果一个 fbo 设置为 read_framebuffer,并且默认设置为 draw_framebuffer,那么在“glBlitFramebuffer”操作期间是否也会复制“clear coloured”像素?

如果不是,则无法确定我的目标 FBO 是否实际正在渲染,因为无论如何该颜色都不会复制。

如果是,那么我应该看到红色,我不知道我的 FBO 设置出了什么问题...


正如我之前所说,我一直在尝试开发延迟着色系统。该系统要求我在 FBO 中执行所有操作,然后将其全部渲染回默认 FBO。

由于它不工作,我已经简化了它的过程,要么将基本场景直接渲染到默认 FBO(可以工作),要么将其渲染到目标 FBO 并按照程序将该 FBO 复制回默认 FBO(不起作用)。

我尝试使用的帧缓冲区设置与我一直关注的教程相同:

glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
glGenTextures(1, &m_finalTexture);
glBindTexture(GL_TEXTURE_2D, m_finalTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, m_finalTexture, 0);

我这样渲染我的场景(简化):

//Flush content out of fbo at color attachment 4
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
glDrawBuffer(GL_COLOR_ATTACHMENT4);
glClear(GL_COLOR_BUFFER_BIT);

//Render scene to m_fbo 
RenderPass();

//Swap default FBO back ("0"), read from target fbo (m_fbo)
//Draw target fbo onto default fbo
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
glDrawBuffer(GL_COLOR_ATTACHMENT4);
glReadBuffer(GL_COLOR_ATTACHMENT4);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);

我在每一步都检查了我的帧缓冲区状态,我没有收到任何错误。


我发现了实际问题,等我完全理解后,我会在这里更新这篇文章,提供更多信息。

【问题讨论】:

m_dfbo 也是 FBO?你如何真正验证整个事情是否有效?您是否在某个时候复制到默认帧缓冲区? 是的。我使用变量 m_dfbo 作为“默认 fbo”,无论如何它等于 0。我更新了开头的帖子并将 m_dfbo 更改为“0”以更简洁。 【参考方案1】:

此调用顺序无效:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
...
glDrawBuffer(GL_COLOR_ATTACHMENT4);

GL_COLOR_ATTACHMENT4 不是默认帧缓冲区的有效绘制缓冲区。仅当当前绘制帧缓冲区是 FBO 时才有效。对于默认的帧缓冲区,您需要使用:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
...
glDrawBuffer(GL_BACK);

这将允许glBlitFramebuffer() 复制到默认帧缓冲区的后台缓冲区中。

【讨论】:

我试过没有用,即使 GL_BACK_LEFT 正如维基页面所暗示的那样似乎没有任何区别。帧缓冲区通常存储缓冲区的最后配置,对吗?如果是这种情况,那么从目标 FBO 复制到默认 FBO 时,即使从不为默认 FBO 指定绘图缓冲区(并使用默认配置)也将不起作用 嗯,不知道还有什么问题。 glTexImage2D() 的参数看起来有点奇怪,但我认为它们应该仍然有效。我会使用GL_RGBAGL_UNSIGNED_BYTE 作为格式和类型参数。 感谢您仍然容忍我。我也进行了这些更改,但无济于事。 @Yattabyte 您没有在原始代码中显示glClearColor() 调用。是在 glClear() 调用 FBO 之前将其设置为红色的调用吗? 是的,是的。我已经删除了除一个之外的所有内容(在渲染器的初始化中)。我已经按照您建议的更改再次进行了该测试,但是结果是一样的。【参考方案2】:

一直以来的问题是,如果在主渲染类之外完成绑定默认帧缓冲区的调用,将无法正常工作。 所以我把这条线从我的 GBuffer 移到我的主渲染类中,并在调用 GBuffer.FinalPass(); 之前执行了它;

【讨论】:

以上是关于从一个帧缓冲区读取到另一个帧缓冲区时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

渲染到纹理时出现黑屏

Android OpenGLES3绘图 - 帧缓冲

渲染到(或读取?)帧缓冲区在移动 Safari 中不起作用

在 DS 上结合 3D 和帧缓冲模式

如何将视频帧保存到缓冲区中?

使用帧缓冲的两个应用程序