OpenGL中的Frame Buffer Object 理解

转载 2016年05月31日 19:26:10

点击打开链接

概要

在OpenGL的渲染管线中,几何数据和纹理通过一系列变换和测试,最终被渲染成屏幕上的二维像素。那些用于存储颜色值和测试结果的二维数组的几何被称为帧缓冲区(frame buffer)。这些二维数组按用途划分,可分为颜色缓冲区(color buffer),深度缓冲区(depth buffer),模版缓冲区(stencil buffer)和累加缓冲区(accumulation buffer)。当我们创建了一个可供OpenGL绘制用的窗体后,窗体系统会为我们生成一个默认的帧缓冲区,这个帧缓冲区完全是由窗体系统来管理的,且仅用于将渲染后的图像输出到窗口的显示区域。

 

然而,我们可以使用OpenGL提供的GL_EXT_framebuffer_object扩展功能来创建额外的帧缓冲区。GL_EXT_framebuffer_object扩展功能中,提出了帧缓冲区对象(framebuffer object,缩写为FBO,下文中将使用FBO来代表帧缓冲区对象)的概念,用于对帧缓冲区进行建模。这样一来,无论是窗体系统创建的帧缓冲区,还是用于屏外渲染的帧缓冲区,都是FBO的实例。有了FBO,程序员就可以重定向渲染目标到其他的存储空间,比如将渲染目标重定向到纹理空间,实现渲染到纹理功能(Render to Texture)。

 

上文提到过帧缓冲区中包含的二维数组按用途划分,可分为颜色缓冲区(color buffer),深度缓冲区(depth buffer),模版缓冲区(stencil buffer)和累加缓冲区(accumulation buffer)。FBO中也提供了与颜色缓冲区、深度缓冲区和模版缓冲区相对应的功能(注意,FBO没有提供与累加缓冲区对应的功能)。但是,这并不意味着FBO会直接为这些缓冲区分配空间。FBO只是为这些缓冲区提供一个或多个挂接点。我们需要分别为各个缓冲区创建对象,申请空间,然后挂接到相应的挂接点上。FBO提供的挂接点如下图所示。

clip_image002

可以看出,FBO提供了多个颜色缓冲区挂接点GL_COLOR_ATTACHMENT0_EXT ... GL_COLOR_ATTACHMENTn_EXT、一个深度缓冲区挂接点GL_DEPTH_ATTACHMENT_EXT和一个模板缓冲区挂接点GL_STENCIL_ATTACHMENT_EXT。颜色缓冲区挂接点的个数是因不同厂商和不同型号的显卡而异的。你可以通过GL_MAX_COLOR_ATTACHMENTS_EXT查询当前显卡所支持的颜色缓冲区挂接点的最大个数。FBO提供多个颜色缓冲区挂接点的用意是,允许程序员进行多目标渲染(使用GL_ARB_draw_buffers扩展功能)。

 

能够与FBO挂接的对象有两种,一种是纹理对象(texture object),另一种是渲染缓冲区对象(renderbuffer object)。纹理对象,就是我们平日为模型设置纹理贴图时使用的对象;而渲染缓冲区对象可以用作不具有纹理格式的缓冲区,如深度缓冲区和模板缓冲区。当然,渲染缓冲区对象也可以用来渲染场景。

 

前面提到过,窗体系统创建的帧缓冲区也有对应的FBO的实例。但是,这个FBO与其他通过手工创建的FBO相比有许多不同。第一,通过手工创建的FBO不能用于将渲染结果直接显示到窗口输出区,通过手工创建的FBO只能用于屏外渲染(Off-screen Rendering);第二,窗体系统生成的FBO在创建的时候就拥有颜色缓冲区,深度缓冲区,模版缓冲区,且创建后就为这些缓冲区分配了空间。而手工创建的FBO需要手动为其添加各个缓冲区,并为其申请空间。窗体系统创建的FBO中的各个缓冲区对象不能与手动创建的FBO的挂接点挂接,反之亦然。

 

创建、绑定和删除一个FBO

我们可以使用glGenFramebuffersEXT()来向OpenGL申请一个或者多个闲置的FBO的ID。注意,就算成功地申请到了闲置的ID,OpenGL也不会马上为其创建实例。只用当调用glBindFramebufferEXT ()绑定FBO的时候OpenGL才会真正的创建一个FBO实例(这和其他glBind*函数极为相似)。在FBO被绑定之后,这个FBO就会被OpenGL当作当前的操作对象,后续的操作都被视为对被绑定的FBO进行的操作。窗体系统创建的FBO的ID默认为0。我们可以通过调用glDeleteFramebuffersEXT()函数来释放FBO的实例,如果要删除的FBO实例正在被使用,则OpenGL会自动绑定窗口系统创建的FBO(ID为0)。

 

渲染缓冲区对象

FBO创建完成后,还不能对其进行什么实质性的操作。因为,FBO的各个挂接点上还没有挂接实际的存储对象。我们需要手动创建这些对象,并将其与既存的FBO对象进行挂接。上文提到过,能够与FBO挂接的对象有两种,一种是纹理对象(texture object),另一种是渲染缓冲区对象(renderbuffer object)。读者可能对纹理对象比较熟悉,因为在为模型进行纹理贴图的时候,经常要使用这种对象。然而,对于渲染缓冲对象,读者可能会不太熟悉,因为这是OpenGL扩展中新引入的功能。下文将着重介绍渲染缓冲区对象的内容。

 

渲染缓冲区对象主要是为了实现屏外渲染(Off-screen Rendering)而设计的。渲染缓冲区对象主要用做FBO的深度缓冲区和模板缓冲区。可以使用glGenRenderbuffersEXT()函数来申请一个或多个闲置的渲染缓冲区对象ID(非负整数)。ID 0被OpenGL所保留。注意,申请了闲置ID之后,OpenGL并没有创建实际的对象,需要调用glBindRenderbufferEXT()函数来绑定并创建实际的对象。如果绑定ID 0,OpenGL会解除先前设定的渲染缓冲区对象。

 

上文提到过,渲染缓冲区对象实际上是某种二维数组的抽象。在绑定了一个渲染缓冲区对象之后,需要使用glRenderbufferStorage()函数为其分配二维数组存储空间。注意,同一个FBO中的各个二维数组空间的行数(或列数)应该相同。

 

同FBO类似,可以使用glDeleteRenderbuffersEXT()函数来删除一个渲染缓冲区对象。

 

挂接

可以使用glFramebufferRenderbufferEXT()函数将渲染缓冲区对象挂接到FBO上;使用glFramebufferTexture2D()。如果挂接的ID为0,则OpenGL将解除先前的绑定。当被绑定纹理对象或渲染缓冲区对象被删除,则他们会被自动从当前正在使用的FBO上解除挂接。如果纹理对象或渲染缓冲区对象被挂接到多个FBO上,他们被删除的时候,只会从当前被绑定的FBO上解除挂接,而不会从未被绑定的FBO上解除绑定。

 

FBO的完整性

在向FBO输出渲染结果之前,需要测试FBO的完整性。如果FBO不完整,任何渲染操作都会失败。我们可以使用glCheckFramebufferStatusEXT()函数来测试FBO的完整性(此函数不能在glBegin()和glEnd()函数之间调用)。FBO完整性的判别法则如下:

  • 与FBO挂接的二维数组对象的长度和宽度必须不能为0。
  • 如果一个二维数组对象被挂接到FBO的颜色缓冲区挂接点时,二维数组必须具有内部颜色格式(GL_RGBA, GL_DEPTH_COMPONENT, GL_LUMINANCE等)。
  • 如果一个二维数组对象被挂接到FBO的深度缓冲区挂接点时,二维数组必须具有内部深度格式(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_EXT等)。
  • 如果一个二维数组对象被挂接到FBO的模板缓冲区挂接点时,二维数组必须具有内部模板格式(GL_STENCIL_INDEX, GL_STENCIL_INDEX8_EXT等)。
  • FBO至少挂接有一个二维数组缓冲区对象。
  • 同一个FBO上挂接的二维数组对象必须拥有相同的长度和宽度。
  • 所有的颜色缓冲区挂接点上挂接的二维数组对象必须具有相同的内部格式。

FBO的使用

当所有上述的准备工作都完成之后,就可以调用glBindFramebufferEXT()来绑定一个FBO。随后,就可以像操作窗体系统提供的帧缓冲区一样操作当前绑定的FBO了。日常的3D渲染操作这里不再赘述。这里主要强调像素操作的使用。OpenGL提供了glBlitFramebufferEXT()函数进行像素操作。

 


OpenGL编程指南第十章:Frame buffer

OpenGL在图元rasterazation之后,得到的是fragment,fragment不是最后的像素数据,但和像素对应;fragment需要经过一写了的处理,blend,texture,ligh...
  • longhuihu
  • longhuihu
  • 2013年01月11日 17:21
  • 11878

OpenGL学习归纳 -- buffer的使用总结

1. FrameBuffer是其他Renderbuffer的管理者,
  • lihei12345
  • lihei12345
  • 2014年07月04日 17:26
  • 3647

Frame buffer详解

一、FrameBuffer的原理 FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。 Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供...
  • hedtao
  • hedtao
  • 2012年09月06日 00:27
  • 2318

frame buffer驱动

因为移植的需要,对linux内核的fb驱动进行了封装,但是由于以前没有调试过fb驱动所以还是遇到了很多未知的问题,所以先把封装好的驱动移植到uboot中进行调试,对照uboot以前的fb驱动后对问题进...
  • liaokesen168
  • liaokesen168
  • 2016年08月02日 17:45
  • 549

Android系统Surface机制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的管理分析

在前文中,我们分析了SurfaceFlinger服务的启动过程。SurfaceFlinger服务在启动的过程中,会对系统的硬件帧缓冲区进行初始化。由于系统的硬件帧缓冲区一般只有一个,并且不是谁都可以随...
  • Luoshengyang
  • Luoshengyang
  • 2012年10月15日 00:56
  • 56251

什么叫Frame Buffer Pitch

什么叫Frame Buffer Pitch 在写ARM的显示驱动时,往往能碰到”Frame Buffer Pitch"这个词。 其实最难理解的还是这个“Pitch”,词典的解释是:...
  • desert187
  • desert187
  • 2014年01月09日 17:55
  • 1825

Kinect学习笔记一ColorFrame

开发学习笔记(C#)第一篇 ColorFream的获取与显示 (找到的二代笔记居然是C++,可恶! 自己来写C#。Code摘自SDK。来熟悉程序工作调用流程。 )(XXX?)皆为待议  若看代...
  • hffhjh111
  • hffhjh111
  • 2016年09月11日 11:18
  • 1206

Frame Buffer

Frame buffer,称为帧缓冲器,用于存放显示输出的数据,这个buffer中的数据一般是像素颜色值。 Frame buffer有时也被认为是color buffer(颜色缓冲器)和z ...
  • u012181898
  • u012181898
  • 2016年11月21日 05:11
  • 131

OpenGL编程指南第十章:Frame buffer

OpenGL在图元rasterazation之后,得到的是fragment,fragment不是最后的像素数据,但和像素对应;fragment需要经过一写了的处理,blend,texture,ligh...
  • longhuihu
  • longhuihu
  • 2013年01月11日 17:21
  • 11878

Stencil Buffer(模板缓冲区)

转自:http://www.cnblogs.com/aokman/archive/2010/12/13/1904723.html 与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存...
  • zhw_giser
  • zhw_giser
  • 2014年01月14日 10:36
  • 1207
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OpenGL中的Frame Buffer Object 理解
举报原因:
原因补充:

(最多只允许输入30个字)