天天看点

GLSL使用FBO实现MRT(Multiple Render Targets)绘制到多张纹理

项目的程序里设计需要将某一帧渲染出来的画面拆成三通道单色图像存到三张纹理里面。要绘制到纹理里,自然就想到FBO了。但是一次要输出多张纹理,这个还没接触过。一阵网上搜索过后,终于了解到了MRT(多重渲染目标)。但是网上的教程大部分都使用到了Fragment Shader里的一个预置变量:gl_FragData[]。但是实际使用当中,glsl却报告说这个gl_FragData变量是不建议使用了。于是再经过多方搜索,知道了建议的操作方法是如何实现的。

首先自然是新建一个FBO,然后绑定缓存。一般的FBO我们会绑定一个颜色缓存和一个深度缓存。如果是渲染到纹理,我们就会把一个同样尺寸的纹理绑到颜色缓存中去,比如以下代码:

//新建FBO
GLuint fboId;
glGenFramebuffersEXT(1, &fboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);

//绑定纹理
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
                          GL_TEXTURE_2D, textureId, 0);

//绑定深度缓存
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
                             GL_RENDERBUFFER_EXT, rboId);
           

当然深度缓存也是要预先建好的。那么现在我需要绑定三个纹理,该如何绑定呢?

FBO是提供了不止一个颜色挂接点的。因此,我们可以将第i张纹理绑定到第i个颜色挂接点上。具体一个FBO能有多少个颜色挂接点,可以使用GL_MAX_COLOR_ATTACHMENTS_EXT参数来查询。

因此绑定纹理的代码就变成了:

for(i=0; i<3; ++i)
{
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i,
                          GL_TEXTURE_2D, textureId[i], 0);
}
           

当然纹理数量不能超过颜色挂接点的最大值。

准备工作完成之后,就是实际FBO渲染时的操作。在绑定多个纹理之后,绘制之前还要告诉FBO输出到哪些缓存。使用以下语句:

GLenum mrt[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT};
glDrawBuffers(3, mrt);
           

以上语句先枚举要输出的挂接点,然后使用glDrawBuffers语句来指定。此处绘制3个纹理。这些信息将被传入GLSL当中。

在Fragment Shader里还需要加一些语句:

//此处3个location应当与FBO的GL_COLOR_ATTACHMENTi_EXT对应
layout(location = 0) out vec4 Frag0;
layout(location = 1) out vec4 Frag1;
layout(location = 2) out vec4 Frag2;
           

这里就不用原来的gl_FragColor或者gl_FragData[]变量了,而是用自己指定位置的输出值。然后在Fragment的主循环里可以针对三个输出值做自己需要的处理。

于是绘制完成后,FBO就会将渲染结果存入三张纹理当中,可以进行后续的使用。

参考:

http://blog.csdn.net/xiajun07061225/article/details/7283929

http://blog.csdn.net/yangdelong/article/details/1668673

http://www.cnblogs.com/vertexshader/articles/3022981.html

继续阅读