绑定Framebuffer还是设置ReadBuffer?

Bind Framebuffer or set ReadBuffer?

我创建了一个帧缓冲区:

glBindFramebuffer(GL.GL_FRAMEBUFFER, &fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);

正在通过

从帧缓冲区读取像素
glBindFramebuffer(GL_FRAMEBUFFER, &fbo);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data);

相当于

glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data);

?

这不是等价的,读取 GL_COLOR_ATTACHMENT0 将从当前绑定的帧缓冲区中获取数据,这可能与您创建的完全不同。

所以基本上你需要通过调用

来保证你有你的帧缓冲区绑定
glBindFramebuffer(GL_FRAMEBUFFER, &fbo);

在使用它的任何操作之前。

GL_COLOR_ATTACHMENT0只是Frame buffer对象的一个​​属性,与具体的frame buffer无关。通过使用另一个帧缓冲区绑定调用它,您将读取它的数据,这不是您想要的。

glReadBuffer(GL_COLOR_ATTACHMENT0); glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data);

这里的数据将从当前有界帧缓冲区中读取,这不会等同于

glBindFramebuffer(GL_FRAMEBUFFER, &fbo); glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data); (如果在第一种情况下帧缓冲区未绑定到相应的 fbo)

我认为这就是为什么提供 glNamedFramebufferReadBuffer API 的原因,直接从作为第一个参数提到的帧缓冲区读取数据。

这些是完全不同的调用。让我提供一些关于 FBO 真正含义的背景知识,希望能让这一切变得更加清晰。

帧缓冲区对象(又名 FBO)只是状态的集合。以下调用更改当前绑定的 FBO 中跟踪的状态:

  • glFramebufferTexture2D()
  • glFramebufferRenderbuffer()
  • glDrawBuffers()
  • glReadBuffer()
  • (以及类似调用的其他一些变体)

这意味着无论何时您进行这些调用之一,当前绑定的 FBO 中跟踪的状态都会更新以反映调用的变化。例如,如果您调用 glDrawBuffers(),则更新当前绑定的 FBO 中的绘制缓冲区列表。

然后,任何时候绑定 FBO,FBO 中跟踪的状态将再次变为活动状态。因此,如果您之前在绑定 FBO foo 时调用了 glDrawBuffers(),之后又再次绑定了 foo,则之前调用的绘制缓冲区设置将再次激活。

请注意,FBO 不拥有附属于它的 renderbuffers/textures。 FBO 仅包含有关 哪个 渲染缓冲区在给定连接点连接到 FBO 的信息。在您的代码中,FBO foo 存储渲染缓冲区 rbo 附加到附着点 GL_COLOR_ATTACHMENT0 的事实。例如,将同一个 renderbuffer 附加到多个 FBO 是完全合法的。

现在,更具体地介绍您的代码:

  • glBindFramebuffer() 调用的参数类型错误:

    glBindFramebuffer(GL.GL_FRAMEBUFFER, &fbo);
    

    第二个参数是 FBO 的名称 (id),而不是地址。所以调用是:

    glBindFramebuffer(GL.GL_FRAMEBUFFER, fbo);
    
  • 这个调用什么都不做:

    glReadBuffer(GL_COLOR_ATTACHMENT0);
    

    GL_COLOR_ATTACHMENT0 是 FBO 的默认读取缓冲区。因此,除非您之前将其设置为不同的值,否则此调用是多余的,并且只会设置与默认值相同的值。正如命名所暗示的那样,FBO 可以有多个附件,如果您将 renderbuffer/texture 附加到 ATTACHMENT0 以外的附件,并且想从该附件中读取,则可以使用 glReadBuffer()

只要您只是为 FBO 使用一个附件,您真正需要做的唯一一件事就是绑定您想要阅读的 FBO:

glBindFramebuffer(GL.GL_FRAMEBUFFER, fbo);
glReadPixels(...);

glReadPixels() 总是从当前绑定的 FBO 中读取,所以没有办法解决这个问题。