首页 > 代码库 > 关于FBO(FrameBuffer Object)的一些理解

关于FBO(FrameBuffer Object)的一些理解

  先来整理下本人对FBO的理解。FBO是FrameBuffer Object的首字母简称。翻译过来就是帧缓冲区的意思。根据我的理解,OpenGL作为图形API,可以看做是画笔,帧缓冲区可以比作画布。我们使用OpenGL在帧缓冲区上“作画”(渲染)。

  首先,我们需要建立OpenGL Context,即获得一套“作画”的工具。以Win32 OpenGL为例,我们需要如下流程去建立一个标准的OpenGL Context:

  1、创建一个窗口类(WNDCLASS/WNDCLASSEX)。

  2、注册窗口类(RegisterClass)。

  3、调用CreateWindow/CreateWindowEx创建新窗口,返回窗口句柄 HWND。

  4、创建设备描述符PIXELFORMATDESCRIPTOR pfd。该结构体中包含即将要创建的OpenGL context的各种信息,包括是否支持双缓冲区、像素位数、Z-buffer位数等各种缓冲区位宽。

  5、获取新生成窗口的Device Context句柄HDC hDC,通过调用GetDC(HWND)获得。

  6、调用ChoosePixelFormat(hDC,&pfd)选择合适的像素格式,如果成功,返回像素格式的索引GLuint nPixelFormat。

  7、利用上一步的结果调用SetPixelFormat(hDC,nPixelFormat,&pfd),设置像素格式。

  8、调用wglCreateContext(hDC)获得 OpenGL Context 句柄 HGLRC hRC;

  9、设置上一步获得的OpenGL Context为当前的Context,通过调用wglMakeCurrent(hDC,hRC);

  不总结不知道,一总结发现一步一步下来,步骤还是挺多的。要注意的一点是,上述9步中大部分函数调用是为了生成/申请相关窗口或者句柄,为了提高程序的鲁棒性,需要及时检查返回值的有效性。

  注意:在上述第4步中,我们在设备描述符中通过参数设置了各个缓冲区的位宽。位宽为0当然就是没有这个缓冲区的意思啦。

 


 

  在建立了OpenGL渲染环境之后,相当于获得了一只画笔,而此时我们有一块默认的画布,即我们的屏幕,default framebuffer。我们渲染的目的地就是我们的屏幕,我们画出来的东西,会显示在屏幕上。这个default framebuffer 是与一系列缓冲区相关联的(具体有哪些缓冲区,多少位的缓冲区,是建立OpenGL Context的时候用户自定义的。一般来讲,必要的是颜色缓冲区,深度缓冲区。模板缓冲区、累加缓冲区这俩哥们儿可选。)。我们需要颜色缓冲区来存储我们渲染物体的颜色,需要深度缓冲区来进行深度测试,等等。具体的渲染过程是如何进行的,就是OpenGL Render Pipeline的东西了。在此不细表。

  之后随着新需求的出现和OpenGL的发展,off-screen render技术出现了,即离屏渲染(离线渲染)。我去,off-screen render,离线渲染,乍一听好牛逼的样子,其实很简单。我们把物体直接渲染到屏幕上,就是“在线渲染”。同理,我们把物体渲染到别的地方,不渲染到屏幕上,那不就是“离线渲染”了么。 那我们不渲染到屏幕,渲染到哪儿去呢?

  OpenGL 从某版本之后,引入了Framebuffer Object。 XXXX Object,我们见过很多了,像Vertex Buffer Object, Vertex Array Object。这次的Framebuffer Object是什么东西呢?

  根据本人的理解,FBO(Framebuffer Object)就是OpenGL模拟default framebuffer的功能和结构创建的一种可以作为“画布”使用的Object。也就是说,你生成一个FBO,根据你的渲染需要,捯饬捯饬,然后把你想渲染的东西渲染到你刚生成的这个FBO里面,而不是直接渲染到屏幕上,就是这个样子。Default framebuffer 有很多支撑渲染行为的缓冲区,FBO也可以有,但是要你手动去生成、设置和绑定

  值得注意的是FBO的角色更像是一个管理者,管理着所有支撑渲染的RenderBuffers和Textures,OpenGL没有为FBO分配内存空间去存储渲染所需的几何、像素数据等。但是,FBO有很多Attachment Point,顾名思义,我们把真正起作用的、具有实际内存空间占用的Renderbuffer和Texutures依附在FBO上,FBO起到管理的作用。这点跟VAO有点类似,是一批量“状态”的集合。VAO的事情我觉得有必要再整理下思路,但是此处暂且按下不表。

  最近爱上了Viso作图,如下:

   

  

 

  貌似不能插pdf,只能插图片。不清晰,此处有pdf: http://files.cnblogs.com/chandler00x/FBO.pdf

  下面简单说下两种情况的用法:

  下面这段代码说明如何将Renderbuffer与FBO绑定。

 1 GLuint hFbo,hTex,hDepth,hColor; 2  3     glGenFramebuffers(1,&hFbo); 4     glBindFramebuffer(GL_FRAMEBUFFER,hFbo); 5  6     glGenRenderbuffers(1,&hDepth); 7     glBindRenderbuffer(GL_RENDERBUFFER,hDepth); 8      9     //为当前的Renderbuffer分配空间,格式为GL_DEPTH_COMPONENT,顾名思义 10     //这个Renderbuffer肯定是与depth test相关的。11     glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,m_width,m_height);12 13     //将当前的Renderbuffer与Framebuffer Object的GL_DEPTH_ATTACHMENT的连接点14     //连接起来。再顾名思义,肯定是与Depth test相关的。15     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,hDepth);16 17     glGenRenderbuffers(1,&hColor);18     glBindRenderbuffer(GL_RENDERBUFFER,hColor);19 20     //为当前的Renderbuffer分配空间,格式为GL_RGBA21     glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA,m_width,m_height);22 23     //与FBO的GL_COLOR_ATTACHMENT0连接起来。24     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,hColor);25 26     //检查Framebuffer的完整性,十分必要!!!!!27     //十分必要!!!!!28     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);29     if( status != GL_FRAMEBUFFER_COMPLETE)30         printf("Framebuffer incomplete!\n");31     else32         printf("Framebuffer complete!\n");

 

   下面这段代码说明如何将Texture与FBO绑定。

 

 1 GLuint hFbo,hTex,hDepth,hColor; 2  3     glGenFramebuffers(1,&hFbo); 4     glBindFramebuffer(GL_FRAMEBUFFER,hFbo); 5  6     glGenRenderbuffers(1,&hDepth); 7     glBindRenderbuffer(GL_RENDERBUFFER,hDepth); 8      9     //为当前的Renderbuffer分配空间,格式为GL_DEPTH_COMPONENT,顾名思义 10     //这个Renderbuffer肯定是与depth test相关的。11     glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,m_width,m_height);12 13     //将当前的Renderbuffer与Framebuffer Object的GL_DEPTH_ATTACHMENT的连接点14     //连接起来。再顾名思义,肯定是与Depth test相关的。15     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,hDepth);16 17     glActiveTexture(GL_TEXTURE0);18     glGenTextures(1,&hTex);19     glBindTexture(GL_TEXTURE_2D,hTex);20 21     //为纹理分配空间。22     glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,m_width,m_height,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);23 24     //与FBO的GL_COLOR_ATTACHMENT0绑定,Color。。color。。25     glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,hTex,0);26 27 28     //检查Framebuffer的完整性,十分必要!!!!!29     //十分必要!!!!!30     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);31     if( status != GL_FRAMEBUFFER_COMPLETE)32         printf("Framebuffer incomplete!\n");33     else34         printf("Framebuffer complete!\n");