第十七课,帧缓存(创建和使用方法)

  • Post author:
  • Post category:其他


OpenGL允许我们定义我们自己的帧缓冲,也就是说我们能够定义我们自己的颜色缓冲,甚至是深度缓冲和模板缓冲。



创建一个帧缓冲



1.创建一个帧缓冲对象(Framebuffer Object, FBO)

创建语法同VAO,VBO。

unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);//绑定

GL_FRAMEBUFFER绑定后所有的

读取



写入

帧缓冲的操作将会影响当前绑定的帧缓冲


glBindFramebuffer(GL_READ_FRAMEBUFFER,fbo);

//绑定只读


glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fbo);

//绑定只写



2.纹理附件

颜色附件

unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
	//data == NULL 即仅仅分配了内存而没有填充它

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

附加到帧缓存上

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glFramebufferTexture2D(fbo的类型,颜色附件,纹理类型,纹理,纹理多级渐远级别);

函数原型

glFrameBufferTexture2D(target,attachment,textarget,texture,level);

target:帧缓冲的目标(绘制、读取或者两者皆有)
attachment:我们想要附加的附件类型。当前我们正在附加一个颜色附件。注意最后的0意味着我们可以附加多个颜色附件。我们将在之后的教程中提到。
textarget:你希望附加的纹理类型
texture:要附加的纹理本身
level:多级渐远纹理的级别。我们将它保留为0

attachment附件类型有

颜色纹理

GL_COLOR_ATTACHMENT0+i

, 纹理格式为

GL_RGB


深度缓冲

GL_DEPTH_ATTACHMENT

,纹理格式为

GL_DEPTH_COMPONENT


模板缓冲

GL_STENCIL_ATTACHMENT

,纹理格式为

GL_STENCIL_INDEX


将深度和模板缓冲附加为一个纹理

GL_DEPTH_STENCIL_ATTACHMENT

,纹理格式为

GL_DEPTH24_STENCIL8

,纹理的每32位数值将包含24位的深度信息和8位的模板信息。

使用样例

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);



3.渲染缓冲对象附件

渲染缓冲对象附加的好处是,它会将数据储存为OpenGL原生的渲染格式,它是为离屏渲染到帧缓冲优化过的。

渲染缓冲对象直接将所有的渲染数据储存到它的缓冲中,不会做任何针对纹理格式的转换,让它变为一个更快的可写储存介质。



创建一个渲染缓冲对象
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);


创建一个深度和模板渲染缓冲对象可以通过调用glRenderbufferStorage函数来完成
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);


附加这个渲染缓冲对象
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);



4.选用 纹理附件 还是 渲染缓冲对象附件

通常的规则是,如果你不需要从一个缓冲中采样数据,那么对这个缓冲使用渲染缓冲对象会是明智的选择。如果你需要从缓冲中采样颜色或深度值等数据,那么你应该选择纹理附件。性能方面它不会产生非常大的影响的。



5.调用glCheckFramebufferStatus,检查帧缓冲是否完整。

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;



渲染到纹理

我们将会将场景渲染到一个附加到帧缓冲对象上的颜色纹理中,之后将在一个横跨整个屏幕的四边形上绘制这个纹理。

// framebuffer configuration
    // -------------------------
    unsigned int framebuffer;//创建一个帧缓冲对象
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);//绑定
    
    // 创建一个颜色附件
    unsigned int textureColorbuffer;
    glGenTextures(1, &textureColorbuffer);
    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);//绑定
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);// 将它附加到当前绑定的帧缓冲对象

    // 添加一个深度(和模板)附件到帧缓冲中。
    unsigned int rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // 创建为一个深度和模板附件渲染缓冲对象
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // 附加到帧缓冲的深度和模板附件上
    
    // 检查帧缓冲是否是完整的
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;

	//解绑帧缓冲,保证我们不会不小心渲染到错误的帧缓冲上。
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

在该帧缓存对象中,颜色缓冲绑定为附件(texture),而深度和模板缓冲绑定为渲染缓冲对象。

在循环中使用

 // 绑定到framebuffer并绘制场景,就像我们通常给纹理着色一样
 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
 glEnable(GL_DEPTH_TEST); // 启用深度测试(在渲染屏幕空间四边形时禁用)
 // 确保我们清除了framebuffer的内容
 glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	绘制内容,将绘制在该帧缓存中.................

glBindFramebuffer(GL_FRAMEBUFFER, 0); // 返回默认
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 
glClear(GL_COLOR_BUFFER_BIT);

//绘制到屏幕
screenShader.use();
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);	// use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);



运行结果

在这里插入图片描述

线框模式下为

在这里插入图片描述

帧缓存将3D模型转换为2D纹理。



版权声明:本文为weixin_44518102原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。