[OpenGL 超级宝典][笔记] 8.2 帧缓冲区(FBO)

帧缓冲区对象(FrameBufferObject)

OpenGL将绘制帧缓冲区到一个对象所需要的状态进行封装,叫帧缓冲区对象。

  • 默认帧缓冲区对象与创建的OpenGL窗口相关联,并且在一个新环境被绑定时自动进行绑定。
  • FBO 是一种容器,可以保存其它确实有内存存储并且可以进行渲染的对象,如纹理或渲染缓冲区。

帧缓冲区(FBO)使用:

帧缓冲区的创建,示例代码如下:

    // Step1: 为新缓冲区创建名称
    gluint fboName;
    glGenFramwbuffers(1, &fboName);

    // Step2: 绑定一个新的FBO来修改和使用它
    // 同一时间,只有一个FBO绑定进行绘制,或一个FBO进行绑定记取。
    // GL_READ_FRAMEBUFFER 
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);

    //解除当前的缓冲区绑定,再次绑定到默认的FBO, 这一步可选。读取与写入再次绑定到帧缓冲区。
    //glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

    //Step3: 用完缓冲区后,销毁FBO
    glDeleteFramebuffers(1, &fboName);

渲染缓冲区对象(RBO)

渲染缓冲区对象是一种图像表面,它是专门为了绑定到FBO而设计的。一个渲染缓冲区对象可以是一个颜色表面,模板表面或深度/模板组合表面,也可以一次性绘制很多颜色缓冲区。

创建

创建完RBO,并申请缓冲区大小,程序代码如下

// step1: 创建RBO并给名字
glGenRenderbuffers(3, renderBufferNames);

// Step2: 绑定点的唯一合法目标是:GL_RENDERBUFFER
glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[0]);

// Step3: 分配支持RBO的内存空间。RBO在创建时没有初始存储,就没有什么东西可渲染。
glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[0]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight);
glBindRenderbuffer(GL_RENDERBUFFER, depthBufferName);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, screenWidth, screenHeight);

绑定

RBO绑定到FBO上.其中,第一个参数可能是GL_DRAW_FRAMEBUFFER,也可以是GL_READ_FRAMEBUFFER, 取决于绑定到哪?第三个参数是GL_RENDERBUFFER, 最后一个参数是着色器缓冲区名称。

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    GL_RENDERBUFFER, depthBufferName);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    GL_RENDERBUFFER, renderBufferNames[0]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    GL_RENDERBUFFER, renderBufferNames[1]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    GL_RENDERBUFFER, renderBufferNames[2]);

RBO的特性:
- 一个FBO,可以支持多个RBO
- 大小不同的RBO, 可以绑定到同一个帧缓冲区上


绘制缓冲区

要得到对渲染缓冲区的访问,需要有二个重要步骤。
- 片段着色器设置正确
- 确保输出被引导到正确的位置

着色器输出,需要为着色器配置为写入多重颜色输出,一种方法是写入到gl_FragData[n]内建输出中。n 为着色器的输出索引。

//  multi-buffer.fs
#version 150

in vec4 vFragColor;
in vec2 vTexCoord;

uniform sampler2D textureUnit0;
uniform int bUseTexture;

uniform samplerBuffer lumCurveSampler;

void main(void)
{
    vec4 vColor;
    vec4 lumFactor;
    if(bUseTexture != 0)
    {
        vColor = texture(textureUnit0, vTexCoord);
    }
    else
    {
        vColor = vFragColor;
    }

    gl_FragData[0] = vColor; // 对第一个缓冲区进行原样输出
    float grey = dot(vColor.rgb, vec3(0.3, 0.59, 0.11));
    gl_FragData = ve4(grey, grey, grey, 1.0f);

    vColor = clamp(vColor, 0.0f, 1.0f);

    int offset = int(vColor.r * (1024 -1));
    lumFactor.r = texelFetch(lumCurveSample, offset).r;

    offset = int(vColor.g * (1024-1));
    lumFactor.g = texelFetch(lumCurveSample, offset).g;

    offset = int(vColor.b * (1024-1));
    lumFactor.b = texelFetch(lumCurveSample, offset).b;

    lumFactor.a = 1.0f;
    gl_FragData[2] = lumFactor;
}

缓冲区映射:

缓冲区映射是指通过为每个缓冲区指定颜色绑定来将着色器输出映射到不同的FBO 缓冲区中.也就是说,我们通过glDrawBuffers 来对着色器输出进行路由(route)。这将覆盖以前所有的映射。

GLenum fboBuffs[] = { GL_COLOR_ATTACHMENT0, 
GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };

// 调用glDrawBuffers时,需要确认FBO已经绑定完成.
glDrawBuffers(3, fboBuffs);

同理,glReadBuffers可以设置读取缓冲区。


帧缓冲区复制数据

使用blit,可以将数据从一点移动到另外一点中。它可以直接,有效的bit级数据内存复制。Blit(Bit-Level-Image-Transfer)。

主要使用的接口函数如下:
void glBlitFramebuffer(GLint srX0, GLint srY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dsxY1,
GLBitfield mask, GLenum filter);

常用用法如下:
- glReadBuffer 指定读取缓冲区,glDrawBuffer 指定当前绘制的缓冲区。
- 我们可以将读取和绘制缓冲区设置为同一个 FBO, 同时,将一个FBO 绑定到GL_DRAW_FRAMEBUFFER 和 GL_READ_FRAMEBUFFER绑定,我们将数据一个缓冲区一部分复制到另一部分。
- filter 可以是 GL_LINEA或 GL_NEAREST. 但是深度与模板数据时,必须为GL_LINEA.

你可能感兴趣的:(gpu,opengl)