目录
- FBO OverView
- FBO 优点
- 使用FBO的步骤
FBO OverView
FBO(FrameBuffer Object)
指的是帧缓冲对象,实际上是一个可以添加缓冲区容器,可以为其添加纹理或者渲染缓冲区对象(RBO
)
FBO(FrameBuffer Object)
本身不能用于渲染,只有添加了纹理或者纹理缓冲区之后才可以作为渲染目标,而且它仅且提供了三类附着,分别是颜色附着,模板附着和深度附着
和顶点缓冲区不同,FBO
不能通过共享上下文的方式进行共享
在 opengl-es 可以通过共享上下文方式进行共享的资源有:
- 纹理
- shader
- program 着色器程序
- buffer 类对象,比如 VBO,EBO,RBO 等
不能通过共享上下文方式进行共享的资源有:
- VAO 顶点数组对象(非Buffer类对象)
- FBO 帧缓冲对象(非Buffer类对象)
这里需要说明的是,在不可以共享的资源中,FBO
和VAO
属于资源管理型对象,FBO负责管理几种缓冲区,本身不占用资源,VAO负责管理VBO或者EBO,本身也不占用资源
RBO(Render Buffer Object)
是渲染缓冲区对象,是一个由应用程序分配的2D图像缓冲区,渲染缓冲区可以用于分配和存储颜色、深度或者模板值,可以用作FBO中的颜色、深度和模板附着
如果要使用FBO作为渲染目标,首先要为FBO添加连接对象,比如颜色附着需要连接纹理或者渲染缓冲区对象的颜色缓冲区
FBO 优点
默认情况下,opengl-es
通过绘制到窗口系统提供的帧缓冲区,然后将帧缓冲区对应的区域复制到纹理来实现渲染到纹理,但是此方法只有在纹理尺寸小于或等于帧缓冲区尺寸才有效
另一种方式是使用连接到纹理的 Pbuffer
来实现渲染到纹理,但是与上下文和窗口系统提供的可绘制表面切换开销也很大,因此,引入了帧缓冲区对象 FBO
来解决此问题
在 opengl-es
的场景中,有一些成绩不需要渲染到屏幕,比如在后台利用GPU
实现一些图像转换,缩放等操作,这个时候就可以使用FBO
相对于渲染到屏幕,FBO
渲染不改变图像的分辨率,在图像处理算法中比较常用
FBO(FrameBuffer object)
渲染是渲染到离屏的Buffer中,可以使用glReadPixels
的方式将渲染后图像读出来
使用FBO的步骤
- 创建一个 FBO 并且创建一个2D 纹理用于连接 FBO 的颜色附着
glBindFramebuffer
绑定FBOglDrawElements
进行绘制glBindFramebuffer
解绑FBO
如果要等待绘制完成需要添加如下步骤:
glFinish
等待绘制完成- 可以通过
glReadPixels
将绘制的内容保存下来
参考代码如下:
static int initInternal(ESContext* esContext) {UserData *userData = esContext->userData;......// gen bo & bind to textureglGenFramebuffers(1, &userData->FrameBufferObject);glBindFramebuffer(GL_FRAMEBUFFER, userData->FrameBufferObject);// Add color attachementglGenTextures(1, &userData->textureIdFbo );glBindTexture(GL_TEXTURE_2D, userData->textureIdFbo);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, test_width, test_height, 0, GL_RGBA, 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, userData->textureIdFbo, 0);// Add depth attachementglGenRenderbuffers(1, &userData->textureIdDepth);glBindRenderbuffer(GL_RENDERBUFFER, userData->textureIdDepth);glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT16, test_width, test_height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, userData->textureIdDepth);// 检查 FBO 完整性GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);if (status != GL_FRAMEBUFFER_COMPLETE) {printf("Framebuffer not complete: %d\n", status);return GL_FALSE;}userData->dumpCount = 0;return GL_TRUE;
}static int drawLoopInternal(ESContext* esContext) {... // dump fbo bufferglFinish();if(userData->dumpCount < 10) {glBindFramebuffer(GL_FRAMEBUFFER, userData->FrameBufferObject);unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char)*test_width*test_height*4);if(data == NULL) {printf("malloc data failed \n");return 0;}glReadPixels(0, 0, test_width, test_height, GL_RGBA, GL_UNSIGNED_BYTE, data);sprintf(fileName,"./dumpfile/output_%d.ppm", userData->dumpCount);saveImagePPM(fileName, data, test_width, test_height);printf("save %s success!\n", fileName);free(data);userData->dumpCount++;} else {printf("dump finished! exit!\n");exit(0);}
}