OpenGL中的FBO对象(附源码)

在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扩展中新引入的功能。下文将着重介绍渲染缓冲区对象的内容。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/b223bb3907ef86e05d1ff75b38a83045.html