使用带有多个颜色纹理附件的FrameBufferObject

use*_*743 2 shader fbo opengl-es opengl-es-2.0

我正在我的程序中实现高斯模糊效果.为了完成这项工作,我需要在特定纹理中渲染第一个模糊信息(Y轴上的那个)(让我们称之为tex_1)并使用tex_1中包含的相同信息作为第二个渲染过程的输入信息(对于X轴) )填充包含最终高斯模糊结果的其他纹理(让我们称之为tex_2).

一个好的做法应该是创建2个帧缓冲区(FBO),每个缓冲区附加一个纹理,并链接到GL_COLOR_ATTACHMENT0(例如).但我只想知道一件事:

是否可以使用相同的FBO填充这2个纹理?

所以我必须启用GL_COLOR_ATTACHMENT0和GL_COLOR_ATTACHMENT1并将所需的纹理绑定到正确的渲染过程,如下所示:

伪代码:

FrameBuffer->Bind()
{
     FrameBuffer->GetTexture(GL_COLOR_ATTACHMENT0)->Bind(); //tex_1
     {
          //BIND external texture to blur
          //DRAW code (Y axis blur pass) here...
            //-> Write the result in texture COLOR_ATTACHEMENT0 (tex_1)
     }
     FrameBuffer->GetTexture(GL_COLOR_ATTACHMENT1)->Bind(); //tex_2
     {
          //BIND here first texture (tex_1) filled above in the first render pass
          //Draw code (X axis blur pass) here...
            //-> Use this texture in FS to compute the final result
            //within COLOR_ATTACHEMENT1 (tex_2) -> The final result
     }
}
FrameBuffer->Unbind()
Run Code Online (Sandbox Code Playgroud)

但在我看来有一个问题,因为我需要每个渲染过程将外部纹理绑定为我的片段着色器中的输入.因此,纹理的第一个绑定(color_attachment)丢失了!

那么它是否存在使用一个FBO解决我的问题的方法,还是我需要使用2个独立的FBO?

Ret*_*adi 7

我可以想到至少3个不同的选项来做到这一点.当第三人会实际上并不在OpenGL ES工作,但无论如何,我会解释,因为你可能会以其他方式尝试它,它是桌面支持OpenGL.

我将使用伪代码来减少打字并提高可读性.

2个FBO,每个1个附件

这是最直接的方法.您为每个纹理使用单独的FBO.在设置过程中,您将拥有:

attach(fbo1, ATTACHMENT0, tex1)
attach(fbo2, ATTACHMENT0, tex2)
Run Code Online (Sandbox Code Playgroud)

然后进行渲染:

bindFbo(fbo1)
render pass 1
bindFbo(fbo2)
bindTexture(tex1)
render pass 2
Run Code Online (Sandbox Code Playgroud)

1个FBO,1个附件

在这种方法中,您使用一个FBO,并且每次都附加要渲染的纹理.在设置过程中,您只需创建FBO,而无需附加任何内容.

然后进行渲染:

bindFbo(fbo1)
attach(fbo1, ATTACHMENT0, tex1)
render pass 1
attach(fbo1, ATTACHMENT0, tex2)
bindTexture(tex1)
render pass 2
Run Code Online (Sandbox Code Playgroud)

1个FBO,2个附件

这似乎是你的想法.您有一个FBO,并将两个纹理附加到此FBO的不同附着点.在设置期间:

attach(fbo1, ATTACHMENT0, tex1)
attach(fbo1, ATTACHMENT1, tex2)
Run Code Online (Sandbox Code Playgroud)

然后进行渲染:

bindFbo(fbo1)
drawBuffer(ATTACHMENT0)
render pass 1
drawBuffer(ATTACHMENT1)
bindTexture(tex1)
render pass 2
Run Code Online (Sandbox Code Playgroud)

这将渲染到第tex22遍,因为它被附加到ATTACHMENT1,我们将绘制缓冲区设置为ATTACHMENT1.

主要的警告是,这不适用于OpenGL ES.在ES 2.0(不使用扩展)中,它是一个非启动器,因为它只支持单个颜色缓冲区.

在ES 3.0/3.1中,有一个更微妙的限制:它们没有glDrawBuffer()来自完整OpenGL 的调用glDrawBuffers().你会尝试的电话是:

GLenum bufs[1] = {GL_COLOR_ATTACHMENT1};
glDrawBuffers(bufs, 1);
Run Code Online (Sandbox Code Playgroud)

这在完整的OpenGL中完全有效,但会在ES 3.0/3.1中产生错误,因为它违反了规范中的以下约束:

如果GL绑定到draw framebuffer对象,则bufs中列出的第i个缓冲区必须为COLOR_ATTACHMENTi或NONE.

换句话说,渲染的唯一方法GL_COLOR_ATTACHMENT1是至少有两个绘制缓冲区.以下调用有效:

GLenum bufs[2] = {GL_NONE, GL_COLOR_ATTACHMENT1};
glDrawBuffers(bufs, 2);
Run Code Online (Sandbox Code Playgroud)

但是为了使它真正起作用,你需要一个产生两个输出的片段着色器,其中第一个不会被使用.到目前为止,您希望这种方法对OpenGL ES没有吸引力.

结论

对于OpenGL ES,上面的前两种方法都可以使用,并且使用起来都非常好.我不认为有一个非常强烈的理由选择一个而不是另一个.不过,我会推荐第一种方法.

您可能认为仅使用一个FBO可以节省资源.但请记住,FBO是仅包含状态的对象,因此它们使用的内存非常少.创建一个额外的FBO是微不足道的.

大多数人可能更喜欢第一种方法.我们的想法是您可以在安装过程中配置两个FBO,然后只需要glBindFramebuffer()调用它们之间进行切换.绑定不同的对象通常被认为比修改现有对象便宜,这是第二种方法所需要的.