复制 FBO 颜色附件

3
我有两个FBOs+MRT,它们具有相同的附件(每个4个颜色附件)。使用glBlitFrameBuffer对于深度缓冲区和一个颜色附件按预期工作。然而,当我复制多个颜色附件时,情况变得糟糕。我做了很多研究并尝试了许多不同的方法,但都没有奏效。我没有使用renderBufferStorage,因为我的纹理具有不同的内部格式(RGBA和RGB16F)。听起来像是一个类似的问题,只是我没有使用多重采样,只有MRT。
OpenGL版本为4.3
为什么:我想创建地形在光照计算之前的状态,这样只需要在有更改(例如相机移动)时渲染地形,然后将这些颜色附件复制到下一个FBO。这是用于延迟着色,FBOs非常类似于gBuffer。
起初我期望应该使用glDrawBuffers,因为我在初始设置中正在使用它,但是没有glReadBuffers,因此我认为我无法将它们链接起来。我可能在这里错了,还不是专家=)
原始代码是用Golang编写的,应该很容易转换为C++(如果需要,我会翻译)。
更新/解决:对于任何遇到此问题的人,请注意。当您使用glDrawBuffers()并使用对glDrawBuffer()的调用时,您正在覆盖glDrawBuffers()状态。它需要重置为其原始的glDrawBuffers()状态。
更新2:对于那些对此方法感兴趣的人,我可以确认它具有令人难以置信的性能结果,如果您拥有一个非动画世界,并且摄像机不经常移动。对于我的目的来说很棒(RTS),但对于像CS这样的FPS游戏来说,这将是一种非常糟糕的方法。
在blitting之后添加以下内容(特定情况):
var attachments = [4]uint32{gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3}
gl.DrawBuffers(4, &attachments[0])

FBO设置
gl.GenFramebuffers(1, &fbo.ID)
gl.BindFramebuffer(gl.FRAMEBUFFER, fbo.ID)

//setting up color attachments

gl.GenTextures(1, &fbo.Position)
gl.BindTexture(gl.TEXTURE_2D, fbo.Position)
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB16F, windowWidth, windowHeight, 0, gl.RGB, gl.FLOAT, nil)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbo.Position, 0)

//repeated 3 times for the additional color attachments

var attachments = [4]uint32{gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3}
gl.DrawBuffers(4, &attachments[0])

gl.GenRenderbuffers(1, &fbo.DepthBuffer)
gl.BindRenderbuffer(gl.RENDERBUFFER, fbo.DepthBuffer)
gl.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT, windowWidth, windowHeight)
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fbo.DepthBuffer)

gl.BindFramebuffer(gl.FRAMEBUFFER, 0)

现在进入blitting部分。

gl.BindFramebuffer(gl.READ_FRAMEBUFFER, fboIn.ID)
gl.BindFramebuffer(gl.DRAW_FRAMEBUFFER, fboOut.ID)

//works as expected
gl.BlitFramebuffer(0, 0, windowWidth, windowHeight, 0, 0, windowWidth, windowHeight, gl.DEPTH_BUFFER_BIT, gl.NEAREST)

//works as expected
gl.ReadBuffer(gl.COLOR_ATTACHMENT0)
gl.DrawBuffer(gl.COLOR_ATTACHMENT0)
gl.BlitFramebuffer(0, 0, windowWidth, windowHeight, 0, 0, windowWidth, windowHeight, gl.COLOR_BUFFER_BIT, gl.LINEAR)

//fails - no errors but produces some weird occurrences. 
gl.ReadBuffer(gl.COLOR_ATTACHMENT1)
gl.DrawBuffer(gl.COLOR_ATTACHMENT1)
gl.BlitFramebuffer(0, 0, windowWidth, windowHeight, 0, 0, windowWidth, windowHeight, gl.COLOR_BUFFER_BIT, gl.LINEAR)

gl.BindFramebuffer(gl.FRAMEBUFFER, 0)

请编辑您的问题,更清楚地描述问题。您只是说“当我 blit 多个颜色附件时,情况变得糟糕”,并且“没有错误但会产生一些奇怪的现象”,这并没有真正帮助解决问题。看到您的片段着色器也可能很有用。它是否确实写入了所有的颜色附件? - G.M.
2
我在给定的代码片段中没有看到任何明显的错误。我唯一能猜测的是,也许你在下一帧中搞砸了你的绘制缓冲区状态(如果这是在循环中运行的话,你可能不会立即注意到这一点)。glDrawBuffer()基本上撤销了你在FBO设置部分使用glDrawBuffers()所设置的内容。绘制缓冲区状态是按FBO存储的,并且你在blitting时修改了它,但没有恢复它(至少在目前发布的代码片段中没有)。 - derhass
@derhass,你说得完全正确!就在你写这个问题的5分钟前,我才弄明白了 :) 我之前不知道drawBuffer()调用会覆盖drawBuffers()的初始化设置,现在想想也很合理。我只是以为它会返回到原来的FBO状态drawBuffers()状态。 - JensF
1个回答

1

glDrawBuffer(x) 的概念等同于调用 GLenum bufs[1]={x}; glDrawBuffers(1, bufs)。由于绘制缓冲区状态是 FBO 状态的一部分,您的 blitting 代码将覆盖这些状态,如果不手动恢复这些状态,则之后的渲染将无法按预期工作。如果在循环中调用此函数,可能会得出错误结论,即 blitting 是问题所在,但实际上,blitting 正在正确地处理错误的输入数据。


  1. 我原以为在初始化期间设置glDrawBuffers()会与framebuffer绑定并在绑定时激活,就像VAO中的VBO一样。
  2. 同样,我认为glDrawBuffer()和glDrawBuffers()是两个不同的函数,因此它没有“取消”FBO的绘制状态。
当你这样解释时,是的,blit正在执行它应该做的事情,当然,在此之后它不应该恢复绑定,否则可能会引入大量不必要的OpenGL调用。
- JensF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接