【问题标题】:Blitting FBO Color AttachmentsBlitting FBO 颜色附件
【发布时间】:2020-06-22 09:33:57
【问题描述】:

我有 2 个 FBO + MRT,它们有相同的附件(每个附件 4 个颜色)。对于深度缓冲区和 one color_attachment,使用 glBlitFrameBuffer 可以正常工作。但是,当我使用多种颜色的附件时,事情就变糟了。我做了很多研究,尝试了很多不同的方法,都没有奏效。我没有使用 renderBufferStorage,因为我的纹理具有不同的内部格式(RGBA 和 RGB16F)。 This 听起来像一个类似的问题,除了我没有使用多重采样,只使用 MRT。

OpenGL 4.3 版

为什么:我想创建一个地形预照明计算的状态,这样我只需要在有变化时渲染地形(即相机移动),然后将这些颜色附件复制到下一个 FBO。这是用于延迟着色的,FBO 与 gBuffer 非常相似。

起初我希望我应该使用我在初始设置中使用的 glDrawBuffers,但没有 glReadBuffers,因此我假设我无法链接它们。我可能在这里错了,还不是专家=)

原始代码是用 Golang 编写的,应该可以很容易地转换为 C++(如果需要,将进行翻译)。

更新/已解决:对于遇到此问题的任何人。当您使用 glDrawBuffers() 并调用 glDrawBuffer() 时,您将覆盖 glDrawBuffers() 状态。它需要重置为原来的 glDrawBuffers() 状态。

Update2:对于那些对这种方法感兴趣的人,我可以确认它具有令人难以置信的性能结果,如果你有一个非动画世界并且相机不经常移动。就我的目的而言,它很棒 (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)

【问题讨论】:

  • 请编辑您的问题以更清楚地描述问题。你所说的只是"when i blit multiple color attachments, things go bad" 和"no errors but produces some weird occurrences" 这并没有真正的帮助。查看您的片段着色器也可能很有用。它肯定会写入所有颜色附件吗?
  • 我在给定的代码 sn-ps 中看不到任何明显磨损的东西。我仍然可以在这里做出的唯一猜测是,也许你搞砸了 next 帧的绘制缓冲区状态(如果这是循环运行,你可能不会立即注意到这一点)。 glDrawBuffer() 基本上撤消了您在 FBO 设置部分中使用 glDrawBuffers() 设置的内容。绘制缓冲区状态是按 FBO 存储的,您可以针对 blitting 对其进行修改,而无需恢复它(至少在到目前为止发布的代码 sn-ps 中没有)。
  • @derhass 你是绝对正确的!我只是在你写之前 5 分钟才弄清楚这一点 :) 我不知道 drawBuffer() 调用会覆盖 drawBuffers() 初始化设置,现在它很有意义。我只是假设它会回到原来的 FBO 状态 drawBuffers() 状态。

标签: go opengl gpu


【解决方案1】:

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

【讨论】:

  • 1.我认为在初始化期间设置 glDrawBuffers() 它将坚持帧缓冲区绑定,然后在绑定时激活,就像 VAO 中的 VBO。 2. 另外,我认为 glDrawBuffer() 和 glDrawBuffers() 是两个不同的函数,因此它不是“解除绑定”FBO 绘制状态。当你这样解释它时,是的,blit 正在做它应该做的事情和 ofc 是有道理的。它不应该在之后恢复绑定,这可能会引入大量不必要的 OpenGL 调用。
猜你喜欢
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多