FBO【ZT】


FBO本身不是一块内存,没有空间,真正存储东西,可实际读写的是依附于FBO的东西:纹理(texture)和渲染缓存(renderbuffer)。橙书上说纹理是一种复杂组织的数据格式,但是你只要了解它本质也是一块内存区域好了(确切一点:缓存)。至于renderbuffer,有depth-renderbuffer和stencil-renderbuffer等等。FBO就好象一个管理这些资源的管理设备那样(情况如同纹理对象管理纹理,所以都叫Object),这个设备有好多个用来标识上述资源的标签(GL_COLOR_ATTACHMENTi_EXT,GL_DEPTH_ATTACHMENT_EXT等等)。至于这个设备怎么工作呢?

本文来源于ZwqXin http://www.zwqxin.com/ , 转载请注明
原文地址:http://www.zwqxin.com/archives/opengl/learn-fbo.html

 

………………………………………………………………………………………………

 

 

 

整个过程是这样的:在预处理中,新建一个FBO对象,用Bind绑定到当前(这些BIND之类函数一般是表示“你接下来要处理这个对象啦”的意思),给FBO输入渲染缓存或纹理,检查FBO状态是否正确,再脱离绑定。渲染过程,在需要它时再一次绑定,指定把接下来的内容渲染到它里面的哪一个渲染缓存或纹理......脱离绑定,使用之。
连我都觉得表意一塌糊涂,所以还是看那文章吧。注意,这里检查状态(glCheckFramebufferStatusEXT)很有必要,不然你连FBO起不起作用都不知道。在渲染到FBO后开始真正的屏幕渲染时,记得先脱离绑定glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0),否则还是继续渲染到FBO的,你可以把这个0看作代表“屏幕”这个主缓冲的代号;因为你渲染到FBO期间改变的东西是会保留下来的(OPENGL是个状态机嘛),你得去除这些影响,包括使用glPushAttrib之类函数;FBO绑定后开始渲染时还要记得glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|.....);因为上面所说的这些改变包括象素格式,我们需要隔绝屏幕渲染时候的像素信息影响FBO渲染,因此你不想受渲染到FBO前的象素信息影响的话,像每帧开始时那样用glClear吧。

本文来源于ZwqXin http://www.zwqxin.com/ , 转载请注明
原文地址:http://www.zwqxin.com/archives/opengl/learn-fbo.html

 

 

 

http://blog.sina.com.cn/s/blog_4062094e0100alvv.html

FBO, Frame Buffer Object

在OpenGL渲染流水线上,几何数据和纹理数据被多次转换、多次测试,最后以2维像素的形式显示在屏幕上。而OpenGL流水线上最后显示阶段像素所在处,称为帧缓存。帧缓存可视为2维数组,或OpenGL使用的存储区域,它包括了:颜色缓存、深度缓存、模板缓存和累积缓存。
一般情况下,帧缓存由window系统生成并管理,供OpenGL使用。这种缺省的帧缓存称之为“window系统生成”(window-system-provided)的帧缓存。

在OpenGL扩展中,GL_EXT_framebuffer_object提供了另外一种不能够显示的帧缓存接口,帧缓存对象(FBO)。这种帧缓存称之为“应用生成”帧缓存,以区别于“window系统生成”帧缓存。通过使用帧缓存对象(FBO),OpenGL应用程序可以将显示内容输出到“应用生成”帧缓存,而不是传统的“window系统生成”帧缓存。这个过程全部由OpenGL控制。 

和window系统提供的帧缓存一样,FBO也有一组相应存储颜色、深度和模板(注意没有累积)数据的缓存区域。我们把FBO中存储这些数据的区域称之为“缓存关联图像”(framebuffer-attached image)。它完全由OpenGL管理控制。

缓存关联图像分为两类:纹理缓存渲染(显示)缓存(renderbuffer)。如果纹理对象的图像数据关联到帧缓存,opengl执行的将是“渲染到纹理”(render to texture)操作。如果渲染缓存对象的图像数据关联到帧缓存,opengl执行的将是“离线渲染”(offscreen rendering)。

渲染缓存对象是GL_EXT_framebuffer_object中定义的新的一种存储类型。这用于渲染过程中存储单幅2维图像。下面的图1描述了FBO、纹理对象和渲染缓存对象之间的关系。

FBO【ZT】_第1张图片

                                图1 FBO、纹理对象和渲染缓存对象之间的关系

 从图中可以看出,FBO有多个颜色关联:(GL_COLOR_ATTACHMENT0_EXT,..., GL_COLOR_ATTACHMENTn_EXT), 一个深度关联(GL_DEPTH_ATTACHMENT_EXT)和一个模板关联 (GL_STENCIL_ATTACHMENT_EXT)。颜色关联的数目最少有一个,最大数目是与实体的显卡相关的,可以GL_MAX_COLOR_ATTACHMENTS_EXT查询得到。FBO采用多个颜色关联,这样可以同时将多个颜色缓存渲染(绘制)到多个FBO关联存储区,即“多渲染目标”MRT(multiple render target)。MRT可用GL_ARB_draw_buffers完成

注意:FBO本身并没有图像数据存储区,只有多个关联

 

 FBO提供了一种高效的切换机制:将前一个帧缓存关联图像从FBO分离,将一个新的可关联帧缓存图像与FBO关联。FBO对帧缓存关联图像的切换要比对FBO的切换速度更快。用glFramebufferTexture2DEXT(),可以进行二维纹理对象的切换,用glFramebufferRenderbufferEXT可切换渲染缓存对象。

——————————————————————————————————————————————

FBO的生成

FBO的生成过程与VBO的生成过程类似。

glGenFramebuffersEXT()

void glGenFramebuffersEXT(GLsizei n, GLuint* ids) void glDeleteFramebuffersEXT(GLsizei n, const GLuint* ids)

glGenFramebuffersEXT需要两个参数,一个是要生成的帧缓存个数,一个是存储帧缓存ID的地址指针。如果帧缓存的ID为0,表明为缺省的帧缓存,也即window系统生成的帧缓存。

glDeleteFramebuffersExt可用于删除不再使用的FBO。


glBindFramebufferEXT()

void glBindFramebufferEXT(GLenum target, GLuint id)

 一旦生成FBO,可用glBindFramebufferEXT来启用它。第一个参数target应为GL_FRAMEBUFFER_EXT,第二个参数为FBO的ID。如果不再使用FBO,应调用该函数,这时参数ID置为0。

 ———————————————————————————————

渲染缓存对象

 渲染缓存对象是新添加的,专门用于离线渲染。它允许将一个场景直接渲染到一个渲染缓存对象中,而不是渲染到纹理对象。渲染缓存对象是用于存储单幅图像的简单存储对象。该图像是按一种可渲染的内部格式存储。可以说,渲染缓存对象是存储OpenGL的逻辑缓存,它不具有像纹理那样的格式。

_______________________________________________________________________________

glGenRenderbuffersEXT()

void glGenRenderbufferEXT(GLsizei target, GLuint* ids)
void glDeleteRenderbuffersEXT(GLsizei n, const GLuint* ids)

glGenRenderbuffersEXT一旦生成渲染缓存, 返回非零整数。

_________________________________________________________________

glBindRenderbufferEXT()

void glBindRenderbufferEXT(GLenum target, GLuint id)

和其它OpenGL对象一样,你需要在使用它之前对渲染缓存对象进行绑定。其中的target参数应为GL_RENDERBUFFER_EXT。

__________________________________________________________________________________

glRenderbufferStorageEXT()

void glBindRenderbufferEXT(GLenum target, GLuint id)

生成了渲染对象后,还需要分配空间存储数据。glRenderbufferStorageEXT用来完成这件事。该函数的第一个参数必须是GL_RENDERBUFFER_EXT。第二个参数可以是用于颜色的(如GL_RGB, GL_RGBA等等),用于深度的(GL_DEPTH_COMPOENT),用于模板的(GL_STENCIL_INDEX)。渲染缓存存储的图像其大小还是按像素的宽×高来计算,它不得大于常量GL_MAX_RENDERBUFFER_SIZE_EXT;否则会产生GL_INVALID_VALUE的错误。

_________________________________________________________________________________

glGetRenderbufferParameterivEXT()

void glGetRenderbufferParameterivEXT(GLenum target, GLenum param, GLint* value);

 用glGetRenderbufferParameterivEXT可以得到当前渲染对象的属性参数。target必须为GL_RENDERBUFFER_EXT,第二个参数param从下面的常量中取,value为得到返回值的指针。

  GL_RENDERBUFFER_WIDTH_EXT
  GL_RENDERBUFFER_HEIGHT_EXT
  GL_RENDERBUFFER_INTERNAL_FORMAT_EXT
  GL_RENDERBUFFER_RED_SIZE_EXT
  GL_RENDERBUFFER_GREEN_SIZE_EXT
  GL_RENDERBUFFER_BLUE_SIZE_EXT
  GL_RENDERBUFFER_ALPHA_SIZE_EXT
  GL_RENDERBUFFER_DEPTH_SIZE_EXT
  GL_RENDERBUFFER_STENCIL_SIZE_EXT
----————————————————————————————————----

将图像与FBO关联

FBO本身并没有存储任何图像,我们只是将帧缓存可关联图像(纹理和渲染对象)与FBO进行了关联。这种机制可以让我们在FBO中进行帧缓存可关联图像的快速切换。这样就用不着不必要地拷贝,也减少了内存消耗。比如说一个纹理可与多个FBO关联,这样它的图像存储区就能够让多个FBO共享。

    ______________________________________________________________________________________

   将一个纹理关联到FBO

glFramebufferTexture2DEXT(GLenum target,
                          GLenum attachmentPoint,
                          GLenum textureTarget,
                          GLuint textureId,
                          GLint  level)

glFramebufferTexture2DEXT可将2D纹理图像关联到FBO上。第一个参数target必须为GL_FRAMEBUFFER_EXT。参数attachment为FBO上的关联点。FBO上有多个颜色关联点(GL_COLOR_ATTACHMENT0_EXT, ..., GL_COLOR_ATTACHMENTn_EXT),一个GL_DEPTH_ATTACHMENT_EXT和GL_STENCIL_ATTACHMENT_EXT。参数textureTarget大数多情况下为GL_TEXTURE_2D。参数textureId为纹理对象的ID号。参数level为关联的纹理的mipmap等级。

如果textureId取0,则当前关联的纹理将与FBO分离。如果纹理对象被删除了,还它关联着一个FBO的话,该纹理图像会自动与其分离。如果它关联的是多个FBO,它删除时只与当前的FBO分离,不会与其它FBO分离。

______________________________________________________________________________________

   将一个渲染缓存图像关联到FBO

glFramebufferRenderbufferEXT(GLenum target,
                          GLenum attachmentPoint,
                          GLenum renderbufferTarget,
                          GLuint renderbufferId)

渲染缓存图像可用glFramebufferRenderbufferEXT,来与FBO关联。参数target和attachmentpoint和前一个函数glFramebufferTexture2DEXT一样。第三个函数必须为GL_RENDERBUFFER_EXT, 参数renderbufferId为渲染对象的Id。

如果renderbufferId设为0,当前FBO中的渲染图像将与其分离。如果渲染对象删除时还与FBO关联着,那它会自动与当前的FBO分离,但不会与其它关联的FBO分离。

 ----————————————————————————————————----

检查FBO状态

 在图像(纹理或渲染缓冲)与FBO关联,在招待FBO的操作之前,都需要对FBO的状态进行检查。获取FBO状态函数为glCheckFramebufferStatusEXT。如果FBO不完整,那么绘制和读取的命令(glBegin(), glCopyTexImage2D()等)都会失败。

GLenum glCheckFramebufferStatusEXT(GLenum target);

glCheckFramebufferStatusEXT对当前帧缓存的参数和相关联的图像进行验证。注意该函数不能在glBegin()/glEnd()函数对中间使中。target参数必须为GL_FRAMEBUFFER_EXT。它返回一个非零的状态值。如果FBO通过了检查,则返回GL_FRAMEBUFFER_COMPLETE_EXT。

   FBO必须满足以下条件:

  • 关联图像的宽高不能为0;
  • 如果关联图像关联的是颜色关联点,那么图像必须为颜色可渲染的内部格式(如GL_RGBA,  GL_DEPTH_COMPONENT, GL_LUMINANCE等);
  • 如果关联图像关联的是GL_DEPTH_ATTACHMENT_EXT,图像必须是深度可渲染的内部格式(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_EXT等)。
  • 如果关联图像关联的是GL_STENCIL_ATTACHMENT_EXT,图像必须是模板可渲染的内部格式(GL_STENCIL_INDEX, GL_STENCIL_INDEX8_EXT等)。
  • FBO必须至少有一个图像关联;
  • 所有关联到颜色关联点的图像必须使用同一个内部格式。

注意,即使所有的条件都得到满足,opengl驱动程序可能也不支持某些内部格式和参数的组合。如果出现这种情况,glCheckFramebufferStatusEXT将返回GL_FRAMEBUFFER_UNSUPPORTED_EXT.

   ----————————————————————————————————----

示例:渲染到纹理

 示例源程序:fbo.zip

有时,你可能需要生成动态的纹理,如做镜面效果、动态立方体/环境贴图、阴影等效果时。动态纹理

可以通过将渲染的场影绘制到纹理上来完成这些效果。传统解决渲染到纹理的方法是将场景绘制到普通的帧缓存上,然后用glCopyTexSubImage2D拷贝帧缓存图像到纹理上。

使用FBO,我们可以直接将场景绘制到纹理上,而用不着window系统提供的帧缓存。而且,我们可以减少数据拷贝(从帧缓存到纹理)的过程。

例程中提供了用FBO和不用FBO来完成渲染到纹理的代码,以例比较它们的性能。除了性能上的优点,如果纹理分辩率大于无FBO模式下渲染窗口的大小,窗口区域外的部分将被裁剪,但FBO不会出现这种问题。你可以生成比显示窗口大得多的帧缓存图像

   以下代码在渲染循环启动之前,先对FBO和帧缓存可关联图像进行了设置(初始化)。程序中,不仅纹理图像关联到FBO,一个渲染缓存图像也关联到FBO的深度关联点。我们并没有实际用到这个深度缓存,只不过,FBO本身需要用它来做深度测试。我们如果没有把一个深度可渲染图像关联到FBO,那么可能会因为不能进行深度测试而无法进行成功渲染。如果渲染过程中需要模板测试,也可以在程序中加上可渲染图像与GL_STENCIL_ATTACHMENT_EXT关联。

FBO【ZT】_第2张图片

渲染到纹理的过程和普通绘制过程一样。我们只需将渲染的目的地放在FBO即可。FBO【ZT】_第3张图片

注意,glGenerateMipmapEXT()也是作为FBO扩展的一部分,用于在修改纹理图像的基级(base level)之后,显式生成mipmap。如果GL_GENERATE_MIPMAP设置为GL_TRUE,glTex{Sub}Image2D()和glCopyTex{Sub}Image2D()将激活自动mipmap的生成。然而,在纹理的基级修改后,FBO不会自动生成它的MIPMAP。这是因为FBO不调用glCopyTex{Sub}Image2D()来修改纹理。因此,glGenerateMipmapEXT()必须显式的调用来生成mipmap。

 

 

 

http://hi.baidu.com/jrsnail/blog/item/7c4510645d5327e3f73654bc.html

OpenGL中FBO的概念及其应用
2011-01-29 16:02

FBO一个最常见的应用就是:渲染到纹理(render to texture),通过这项技术可以实现发光效果,环境映射,阴影映射等很炫的效果。

OpenGL中的Frame Buffer Object(FBO)扩展,被推荐用于把数据渲染到纹理对像。相对于其它同类技术,如数据拷贝或交换缓冲区等,使用FBO技术会更高效并且更容易实现。

在OpenGL渲染管线中,几何数据和纹理最终都是以2d像素绘制到屏幕上。最后一步的渲染目标在OpenGL渲染管线中被称为帧缓存(frame buffer)。帧缓存是颜色缓存、深度缓存、模板缓存、累积缓存的集合。默认情况下, OpenGL使用的帧缓存是由窗体系统创建和管理的。

在OpenGL扩展中,GL_EXT_framebuffer_object扩展提供了一个创建额外帧缓存对象(FBO)的接口。这个帧缓存的创建和控制完全是由OpenGL完成的,有别于窗体系统创建的默认的帧缓存。与系统默认的帧缓存类似,一个FBO也是颜色缓存、深度缓存、模板缓存的集合(FBO不包括累积缓存),然后OpenGL程序就可以把渲染重定向到FBO中。

这里有一个新的概念需要注意,那就是renderbuffer object。这个对象是通过GL_EXT_framebuffer_object扩展创建。它被用来在渲染过程中为一个2D图像提供渲染目标。

下图展示了FBO和renderbuffer object与texture object之间的关系。从图中我们可以看出:多个renderbuffer object和texture object可以通过挂接点挂接到FBO上。需要主要的是FBO并没有实际存储数据的地方,它只是一个数据的壳,它只有挂接点。

FBO【ZT】_第4张图片

一个FBO对象包含多个颜色挂接点和一个深度挂接点以及一个模板挂接点。不同的显卡支持的颜色挂接点的数目是不同的,可以通过查询GL_MAX_COLOR_ATTACHMENTS_EXT获取支持的最大的挂接点的数目。支持多个颜色挂接点的原因是FBO可以在同一时间内将颜色缓存渲染到多个目标中去,这种能力被称为MRT(multiple render targets)。通过GL_ARB_draw_buffers扩展可以实现该功能。

帧缓冲提供了一种有效的切换机制,使得挂接和卸载一个可挂接的图像非常之迅速。FBO使用glFramebufferTexture2DEXT()来进行texturebuffer对象的切换,使用glFramebufferRenderbufferEXT()来进行renderbuffer对象的切换。

让我们看一下其使用过程:
1.FBO对象的创建与销毁
void glGenFramebuffersEXT(GLsizei n, GLuint* ids);
void glDeleteFramebuffersEXT(GLsizei n, const GLuint* ids);
第一个参数是要创建的FBO的个数,第二个保存创建的FBO的ID。

2.一旦FBO对象创建完毕,即要进行绑定
void glBindFramebufferEXT(GLenum target, GLuint id);
第一个参数必须是GL_FRAMEBUFFER_EXT
第二个参数是第一步创建FBO对象中获取的id号,该id号是一个非0值,因为系统默认的FBO的id号是0,所以如果你想取消FBO的绑定,将id等于0作为id参数传递给该函数即可。

3.创建Renderbuffer Object
void glGenRenderbuffersEXT(GLsizei n, GLuint* ids);
void glDeleteRenderbuffersEXT(GLsizei n, const GLuint* ids);

4.同样的,Renderbuffer Object创建好之后,要记得绑定。
void glBindRenderbufferEXT(GLenum target, GLuint id)

5.确定Renderbuffer Object的数据格式和尺寸。
  这一步很重要,因为我们只是创建了Renderbuffer Object,还没有为它提供一个存储数据的地方,也没有指定其存储数据的地方存储什么格式的数据,所以接下来就要做这个事情了。
void glRenderbufferStorageEXT(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
第一个参数必须是GL_RENDERBUFFER_EXT
第二个参数可以是可渲染的颜色格式,如(GL_RGB, GL_RGBA, etc.),可渲染的深度格式(GL_DEPTH_COMPONENT)或者是可渲染的模板格式(GL_STENCIL_INDEX)。
最后两个参数就是以像素为单位指定数据所要占用内存的大小。

这里需要注意两点:
1。 指定的内存区域的宽和高应该都小于GL_MAX_RENDERBUFFER_SIZE_EXT,否则将产生GL_INVALID_VALUE错误。
2。 所有的texture object也好,renderbuffer object也好,其宽和高都是严格一致的。

6.指定挂接的对象
glFramebufferTexture2DEXT函数挂接一个texture图像到FBO
glFramebufferRenderbufferEXT函数挂接一个Renderbuffer图像到FBO

7.检测FBO状态
该挂接的对象都挂接好了,在使用FBO之前,必须要检查FBO的状态是否处于完成状态。如果FBO处于未完成状态,那么绘制操作就会失败。如何获取FBO的完成状态呢?使用
glCheckFramebufferStatusEXT函数。

至此,关于FBO的概念及其使用就算告一段落了。下面给出一个完整的例子,该例子是从国外一个网站上找到的,代码写得简单而漂亮,对FBO的演示也很完善。

FBO Demo
http://blog.csdn.net/skylmmm/archive/2011/03/01/6215182.aspx
FBO: framebuffer object.
framebuffer is the final rendering destination of OpenGL pipeline. by default it's created and managed by window system. FBO is non-displayable created by OpenGL.
OpenGL app can redirect the rendering output to the FBO.
FBO contains a collection of rendering destinations: color, depth and stencil buffer. (only default framebuffer has a accumulation buffer.)  these are called framebuffer-attachable images.
there are two types of framebuffer-attachable images: texture images and renderbuffer images.
details: OpenGL Frame Buffer Object (FBO)
CreateFBO()
{
    // Get the currently bound frame buffer object. On most platforms this just gives 0.
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo);
   
    // Generate and bind a render buffer which will become a depth buffer shared between our two FBOs
   /* Note that not only a texture image is attached to the FBO, but also, a renderbuffer image is attached to the depth attachment point of     the FBO. We do not actually use this depth buffer, however, the FBO itself needs it for depth test. If we don't attach this depth renderable     image to the FBO, then the rendering output will be corrupted because of missing depth test. If stencil test is also required during FBO     rendering, then additional renderbuffer image should be attached to GL_STENCIL_ATTACHMENT_EXT.
    */
    glGenRenderbuffers(1, &m_uDepthBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_uDepthBuffer);
    // Create a texture for rendering to
    glGenTextures(1, &m_uiTextureToRenderTo);
    glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
   
    // Create the object that will allow us to render to the aforementioned texture
    glGenFramebuffers(1, &m_uFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, m_uFBO);
    // Attach the texture to the FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTextureToRenderTo, 0);
    // Attach the depth buffer we created earlier to our FBO.
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uDepthBuffer);
}

Render()
{
    // step 1: render the object to "FBO": m_uiTextureToRenderTo
    {
        // Bind our FBO
        glBindFramebuffer(GL_FRAMEBUFFER, m_uFBO);      //绑定FBO,所以以下的都是渲染到FBO中去的
        
        DrawMesh()
       
        // We are done with rendering to our FBO so switch back to the back buffer.
        glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);   //绑定其他的帧缓存。在我们的代码中,就是放弃绑定FBO    
        //即glBindFramebuffer(GL_FRAMEBUFFER, 0); 然后程序的渲染都是渲染到windows的缓冲区中去了,用以显示。
    }
   
    // step 2: use the texture generated in step 1 as a texture.
    {
        // Bind our texture that we have rendered to
        glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
        // Draw our textured cube
        DrawMesh()
    }
}

本文来自CSDN博客,转载请标明出处: http://blog.csdn.net/skylmmm/archive/2011/03/01/6215182.aspx
自我总结:
FBO就是开辟了内存中的一组地址,用以把texture或者renderbuffer渲染到其中,但并不显示出来。
一般而言,windows的帧缓存(framebuffer)就是渲染了以后,直接显示出来的。

你可能感兴趣的:(image,object,ext,存储,buffer,扩展)