OpenGL 帧缓冲绑定目标
Posted
技术标签:
【中文标题】OpenGL 帧缓冲绑定目标【英文标题】:OpenGL framebuffer bind target 【发布时间】:2015-11-08 14:17:37 【问题描述】:当调用glBindFramebuffer(GLenum target, GLuint framebuffer);
时,我知道target
可以是GL_READ_FRAMEBUFFER
、GL_DRAW_FRAMEBUFFER
或GL_FRAMEBUFFER
,两者都是。
但是,当我将纹理或 Renderbuffer 对象附加到帧缓冲区时,我还必须提供绑定目标。
我的问题是,当我通过绑定目标 target
将任何内容附加到帧缓冲区时,它是否保持不变?
这意味着当渲染缓冲区通过绑定点GL_DRAW_FRAMEBUFFER
附加到帧缓冲区时,它将始终是绘图操作的目标,如果我希望从该渲染缓冲区读取,那么我必须再次调用glFramebufferRenderbuffer()
,这次将target
设置为GL_READ_FRAMEBUFFER
。
谁能证实这一点?我问是因为我试图将所有这些封装在 C++ 类中。
【问题讨论】:
【参考方案1】:这意味着当渲染缓冲区通过绑定点 GL_DRAW_FRAMEBUFFER 附加到帧缓冲区时,它将始终是绘图操作的目标,如果我想从中读取该渲染缓冲区,我必须再次调用 glFramebufferRenderbuffer() 并将目标设置为这次是 GL_READ_FRAMEBUFFER。
没有。附件是每个 FBO 状态,它们与 FBO 绑定的绑定点无关。
一个对象可能绑定到语义上不同的绑定目标,但对象本身定义了它的所有状态。例如,您可以将数据加载到绑定为GL_PIXEL_UNPACK_BUFFER
的缓冲区,然后通过将其绑定为GL_VERTEX_ARRAY_BUFFER
将此数据用作顶点属性。
但是,当我将纹理或 Renderbuffer 对象附加到帧缓冲区时,我还必须提供绑定目标。
嗯,那是因为传统的 GL 使用 bind 来修改 语义。如果要操作任何对象的状态,则必须将其绑定到某个目标(当然要匹配对象类型),并且所有状态设置函数都会通过寻址目标来间接引用该对象。这并不意味着修改与绑定点有任何关系。
Bind-to-modify 一直是 OpenGL 的一个经常被批评的原则。很长一段时间以来,一些供应商已经实施了EXT_direct_state_access
扩展来解决这个问题。它提供了直接引用对象而不是间接使用绑定点的函数。在您的示例中,glNamedFramebufferRenderbufferEXT
将允许您直接附加渲染缓冲区,而无需先绑定 FBO。
最终在 OpenGL 4.5 中,直接状态访问被提升为 OpenGL 的核心功能,并创建了ARB_direct_state_access
以允许实现者为早期的 GL 版本提供最终的 API(在某些方面与 EXT 版本不同) .现在有了官方的glNamedFramebufferRenderbuffer()
功能。
【讨论】:
我理解绑定修改语义,但我仍然对这些帧缓冲区对象感到困惑。当我调用glFramebufferRenderbuffer()
时,我将target
设置为GL_READ_FRAMEBUFFER
或GL_DRAW_FRAMEBUFFER
都没有关系,只要是绑定的就行? (glBindFramebuffer()
)
好吧,GL_FRAMEBUFFER
绑定目标只是将它绑定到读取和绘制帧缓冲区的快捷方式。结果,它将绑定在两个目标上,并且通过任何万寿菊修改它都会起作用,因为引用了同一个对象。
我明白了。一个离题的小问题:似乎我可以在我的 Renderbuffer 对象附加到帧缓冲区后调用 glDeleteRenderbuffers() ,并且没有任何不好的事情发生。这是正常的吗?你会建议这样做吗?
@Pilpel:是的,就是这样指定的。您只会丢失对象名称(并且对 glGen*() 函数的进一步调用可能会重用该名称),因此在删除后您不能再引用该对象。只要它仍然被某个容器对象(在本例中为 FBO)引用,对象本身就会被保留。
删除渲染缓冲区时,它会自动与当前绑定的 FBO 分离,但不会与其他 FBO 分离。在第二种情况下,您可能会遇到非常奇怪的情况,即您有多个具有相同名称的对象,因为可以在原始对象仍然存在时重用该名称。我强烈反对为您仍在使用的渲染缓冲区调用 glDeleteRenderbuffers()
。以上是关于OpenGL 帧缓冲绑定目标的主要内容,如果未能解决你的问题,请参考以下文章