简述
一般在OpenGL环境搭建过程中,窗口系统会创建一个默认的帧缓存,这个帧缓存是唯一可以被图形服务器的显示系统所识别的帧缓存,所以应用程序自定义的帧缓存只能用于离屏渲染的场合。帧缓存不会直接存储渲染数据,必须将渲染的结果保存到一些附件中(颜色,深度和模板)。窗口系统的帧缓存在创建之初就有自己的缓存附件,自定义的帧缓存对象还需要手动添加这些附件。
帧缓存的内存模型如下:
红色区域就是实际存储数据的内存空间。
纹理对象
纹理附加到帧缓冲的时候,所有的渲染指令将会写入到这个纹理中,就想它是一个普通的颜色缓冲一样。使用纹理的优点是,所有渲染操作的结果将会被储存在一个纹理图像中,我们之后可以在着色器中很方便地使用它。
渲染缓存对象
渲染缓存是OpenGL所管理的一处高效的内存区域,它可以存储格式化的数据。渲染缓存中的数据只有关联到一个帧缓存对象之后才有意义。由于渲染缓冲对象通常都是只写的,它们会经常用于深度和模板附件,因为大部分时间我们都不需要从深度和模板缓冲中读取值,只关心深度和模板测试。我们需要深度和模板值用于测试,但不需要对它们进行采样,所以渲染缓冲对象非常适合它们。
帧缓存的完整性
纹理和缓存的格式组合是多样的,而且不同的帧缓存附件设置都可能导致帧缓存对象无法正常渲染。因此当创建好帧缓存及其附件后,对其进行一次检测,查看是否成功创建。
帧缓存的无效化
帧缓存会占用相当的系统资源,所以使用完成后需要释放,OpenGL中可以将帧缓冲的一块区域或整体声明为不在使用,并且可以立即释放可以通过函数gllnvalidateSubFramebuffer()和gllnvalidateFramebuffer()完成。
构建帧缓存的步骤
1,创建帧缓存对象,绑定帧缓存对象
glGenFramebuffers()
glBindFramebuffer()
2,创建纹理附件
glGenTextures()
glBindTexture()
3,把纹理附件附加到帧缓冲上
glFramebufferTexture2D()
4,创建一个用于深度和模板附件的渲染缓冲对象并绑定
glGenRenderbuffers()
glBindRenderbuffer()
5,创建一个深度和模板渲染缓冲对象,并给渲染缓冲对象分配空间
glRenderbufferStorage()
6,把模板和深度缓冲对象附加在这个渲染缓冲对象:
glFramebufferRenderbuffer()
7,判断是否创建成功
glCheckFramebufferStatus()
帧缓存实现流程
部分代码
//----------------------构建帧缓存----------------------
glGenFramebuffers(1, &framebuffer);
//绑定到帧缓存,之后所有的读取和写入帧缓冲的操作将会影响当前绑定的帧缓冲
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
//创建颜色附件
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
//对于这个纹理,我们仅仅分配了内存而没有填充它
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 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, 800, 600);
//把模板和深度缓冲对象附加在这个渲染缓冲对象:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
//判断检查帧缓冲是否完整,如果完整,则返回GL_FRAMEBUFFER_COMPLETE
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
}
//解除纹理绑定
glBindTexture(GL_TEXTURE_2D, 0);
//解除渲染缓冲绑定
glBindRenderbuffer(GL_RENDERBUFFER, 0);
//解除帧缓冲绑定
glBindFramebuffer(GL_FRAMEBUFFER, 0);
参见:《OpenGL编程指南》第八版第3章
learnOpengl教程