VBO, PBO与FBO
来源:互联网 发布:淘宝查询礼服秋冬女装 编辑:程序博客网 时间:2024/05/29 08:20
VBO,Vertex Buffer Array
[参考文章3]归纳出VBO扩展的用法流程,并总结出与纹理用法流程的相似性:
初始化阶段:
1. glGenBuffersARB(1, &nVBOVertices); //生成一个句柄
2. glBindBufferARB(GL_ARRAY_BUFFER_ARB, nVBOVertices); //声明该句柄为一个vbo句柄,并选择之
3. glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices), vertices,GL_STATIC_DRAW); //将顶点集上传至server端
使用阶段:
1. glEnableClientState(GL_VERTEX_ARRAY); //开始使用vbo
2. glBindBufferARB(GL_ARRAY_BUFFER_ARB, nVBOVertices);
3. glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
4. glDrawArrays( GL_TRIANGLES, 0, g_pMesh->m_nVertexCount ); //画吧
5. glDisableClientState(GL_VERTEX_ARRAY); //停止使用vbo
收尾阶段:
1. glDeleteBuffersARB(1,&nVBOVertices); //删除句柄,同时删除server端顶点缓冲
再来看看纹理缓冲是怎么使用的,其实差不多:
初始化阶段:
1. glGenTextures(1, &texID);//创建句柄
2. glBindTexture(GL_TEXTURE_2D, texID); //设置句柄类型
3. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img->GetWidth(), img->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, raw_rgba); //上传纹理缓冲
使用阶段:
1. glEnable(GL_TEXTURE_2D); //开始使用纹理缓冲
2. glBindTexture(GL_TEXTURE_2D, texID); //选择当前使用的纹理缓冲
3. 发送顶点和纹理坐标,画吧...省略
4. glDisable(GL_TEXTURE_2D); //停止使用纹理
收尾阶段:
1. glDeleteTextures(1,&texID);//删除句柄,,同时删除server端缓冲
参考文章:
1. NEHE教程第45讲 http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=45
2. http://hi.baidu.com/excerpts/blog/item/dde4e0ceeeee8c0692457e54
3. OpenGL VBO顶点缓冲的使用 http://www.cppblog.com/w2001/archive/2008/05/10/49376.aspx
4. Opengl Vertex Buffer Object http://www.songho.ca/opengl/gl_vbo.html
PBO,即Pixel Buffer Object也是用于GPU的扩展(ARB_vertex_buffer_object)。这里的缓存当然就是GPU的缓存。PBO与VBO扩展类似,只不过它存储的是像素数据而不是顶点数据。PBO借用了VBO框架和所有API函数形式,并加了上两个"target"标志。这两个标识是:
- GL_PIXEL_PACK_BUFFER_ARB 将像素数据传给PBO
- GL_PIXEL_UNPACK_BUFFER_ARB 从PBO得到像素数据
这里的“pack”还是“unpack”,可分别理解为“传给”和“得到”。它们也都可以统一理解为“拷贝”,也就是像素数据的“传递”。
图1 opengl PBO
图2 不使用PBO的纹理载入
图3 使用PBO的纹理载入
生成PBO
映射PBO
____________________________________________________
Demo
例子程序pboUnpack.zip使用了不同方式来比较将纹理传给OpenGL的模式:
- 使用一个PBO;
- 使用两个PBO;
- 不使用PBO;
通过按空格键,可以不同模式间切换。
在PBO模式下,每帧的纹理源(像素)都是在映射PBO状态下直接写进去的。再通过调用glTexSubImage2D将PBO中的像素传递给纹理对象。通过使用纹理对象可以在PBO和纹理对象间进行异步DMA传递。它能大大提高像素传递的性能。
由于glTexSubImage2D立即返回,因此CPU能够直接进行其它工作,无需等待实际的像素传递。
图4 两个PBO更新纹理
为了将像素传递的性能最大化,可以使用多个PBO对象。图4中表明同时使用了两个PBO。在glTexSubImage2D将像素数据从PBO拷贝出来的同时,另一份像素数据写进了另一个PBO。
在第n帧时,PBO1用于glTexSubImage2D,而PBO2用于生成一个新的纹理对象了。再到n+1帧时,两个PBO则互换了角色。由于异步DMA传递,像素数据的更新和拷贝过程可同时进行,即CPU将纹理源更新到PBO,同时GPU将从另一PBO中拷贝出纹理。
例子程序pboPack.zip从窗口的左边读出(pack)像素数据到PBO,在更改它的亮度后,把它在窗口的右边绘制出来。通过按空格键,可以看glReadPixels的性能。
传统使用glReadPixels将阻塞渲染管道(流水线),直到所有的像素数据传递完成,才会将控制权交还给应用程序。相反,使用PBO的glReadPixels可以调度异步DMA传递,能够立即返回而不用等待。因此,CPU可以在OpenGL(GPU)传递像素数据的时候进行其它处理。
图5 用两个PBO异步glReadPixels
例子程序也使用了两个PBO,在第n帧时,应用帧缓存读出像素数据到PBO1中,同时在PBO中对像素数据进行处理。读与写的过程可同时进行,是因为,在调用glReadPixels时立即返回了,而CPU立即处理PBO2而不会有延迟。在下一帧时,PBO1和PBO2的角色互换。
参考文章
1. http://www.songho.ca/opengl/gl_pbo.html
2. http://hacksoflife.blogspot.com/2006/10/vbos-pbos-and-fbos.html
3. http://www.paulsprojects.net/opengl/rtotex/rtotex.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本身并没有图像数据存储区,只有多个关联。
——————————————————————————————————————————————
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()
渲染缓存对象
_______________________________________________________________________________
glGenRenderbuffersEXT()
glGenRenderbuffersEXT一旦生成渲染缓存,
_________________________________________________________________
glBindRenderbufferEXT()
和其它OpenGL对象一样,你需要在使用它之前对渲染缓存对象进行绑定。其中的target参数应为GL_RENDERBUFFER_EXT。
__________________________________________________________________________________
glRenderbufferStorageEXT()
生成了渲染对象后,还需要分配空间存储数据。glRenderbufferStorageEXT
_________________________________________________________________________________
glGetRenderbufferParameterivEXT()
----————————————————————————————————----
将图像与FBO关联
FBO本身并没有存储任何图像,我们只是将帧缓存可关联图像(纹理和渲染对象)与FBO进行了关联。这种机制可以让我们在FBO中进行帧缓存可关联图像的快速切换。这样就用不着不必要地拷贝,也减少了内存消耗。比如说一个纹理可与多个FBO关联,这样它的图像存储区就能够让多个FBO共享。
将一个纹理关联到FBO
glFramebufferTexture2DEX
如果textureId取0,则当前关联的纹理将与FBO分离。如果纹理对象被删除了,还它关联着一个FBO的话,该纹理图像会自动与其分离。如果它关联的是多个FBO,它删除时只与当前的FBO分离,不会与其它FBO分离。
______________________________________________________________________________________
将一个渲染缓存图像关联到FBO
渲染缓存图像可用glFramebufferRenderbuffe
如果renderbufferId设为0,当前FBO中的渲染图像将与其分离。如果渲染对象删除时还与FBO关联着,那它会自动与当前的FBO分离,但不会与其它关联的FBO分离。
检查FBO状态
glCheckFramebufferStatus
- 关联图像的宽高不能为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驱动程序可能也不支持某些内部格式和参数的组合。如果出现这种情况,glCheckFramebufferStatus
示例:渲染到纹理
有时,你可能需要生成动态的纹理,如做镜面效果、动态立方体/环境贴图、阴影等效果时。动态纹理
可以通过将渲染的场影绘制到纹理上来完成这些效果。传统解决渲染到纹理的方法是将场景绘制到普通的帧缓存上,然后用glCopyTexSubImage2D拷贝帧缓存图像到纹理上。
使用FBO,我们可以直接将场景绘制到纹理上,而用不着window系统提供的帧缓存。而且,我们可以减少数据拷贝(从帧缓存到纹理)的过程。
例程中提供了用FBO和不用FBO来完成渲染到纹理的代码,以例比较它们的性能。除了性能上的优点,如果纹理分辩率大于无FBO模式下渲染窗口的大小,窗口区域外的部分将被裁剪,但FBO不会出现这种问题。你可以生成比显示窗口大得多的帧缓存图像。
渲染到纹理的过程和普通绘制过程一样。我们只需将渲染的目的地放在FBO即可。
注意,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://www.gamedev.net/reference/articles/article2331.asp
http://www.physdev.com/articles/
http://www.builder.com.cn/2008/0703/963021.shtml
http://www.songho.ca/opengl/gl_fbo.html
- VBO, PBO与FBO
- VBO, PBO与FBO
- OpenGL VBO, PBO与FBO
- OpenGL VBO, PBO与FBO
- OpenGL VBO, PBO与FBO
- 【转】VBO, PBO与FBO
- VBO, PBO与FBO(三)
- VBO, PBO与FBO(二)
- VBO, PBO与FBO(一)
- VBO, PBO与FBO(一)
- VBO, PBO与FBO(二)
- VBO, PBO与FBO(三)
- VBO,PBO,FBO
- VAO, VBO, PBO, FBO
- OPENGL VBO,FBO和PBO
- OpenGL之VBO,PBO,FBO技术
- OpenGL之VBO,PBO,FBO技术
- VBO、FBO、PBO 学习总结贴 (OpenGL ES)
- Python函数式编程
- gym/101149/ Right Build 有向spfa
- java性能优化
- 4.1使用一个工具窗口创建扩展
- Jensen不等式概率论形式的证明
- VBO, PBO与FBO
- StringUtils常用方法+StringUtils详细介绍
- [设计模式]之代理模式
- 版权声明:本文为博主原创文章,未经博主允许不得转载。 深度残差网络在2015的ILSVRC比赛中获得取得第一的成绩,ICLR2016上也是重点议题之一。 它主要思想很简单,就是在标准的前馈卷积网络
- 安装Docker-compose
- js中typeof的用法
- Hadoop运行本地和伪分布式程序
- 事务的传播行为
- webService 实现原理