帧缓存对象(fbo)主要是用于做渲染到纹理。
opengles2.0渲染到纹理的方法有三种:
第一,使用glCopyTexImage2D或者glCopyTexSubImage2D,这两个函数,复制framebuffer中的
像素到纹理缓存里面,但这两个函数性能比较低下,并且要求纹理的尺寸必须小于等于
framebuffer的尺寸。
第二,使用一个附加到纹理的pbuffer,来执行渲染到纹理的操作。我们知道,窗口系统为我们提供
的surface必须添加到一个渲染环境里面,但是,在某些平台上要求每个pbuffer和窗口系统提供
的surface都需要一个单独的context,所以如果要渲染到pbuffer里面的话,就会发生context的切换,
这种切换操作时很耗时的。
第三,使用fbo,rbo等,这种是最高效的。
Framebuffer和Renderbuffer Object(fbo和rbo):
rbo是一块2D图像缓存,能够用于存储color,depth,stencil值,也就是可以作为
fbo的color或depth或stencil attachment。但是这个rbo不能直接作为纹理使用。
fbo是一个容器,他有三个attachment 点:颜色缓存,深度缓存,和模板缓存的attachment 点。
还保存着,添加到这些attachment点上的颜色缓存,深度缓存,模板缓存的大小、格式等属性,
以及添加进来的纹理和rbo的名字等等。
颜色缓存attachment点,可以添加纹理或rbo。
深度缓存attachment点,可以添加纹理或rbo。
模板缓存attachment点,只能添加rbo。
GL_OES_texture_3D 这个扩展允许3D纹理的2D切添加到attachment点。
GL_OES_depth_texture 这个扩展允许2D深度纹理,和立方体深度纹理。
GL_OES_packed_depth_stencil 这个扩展允许packed depth stencil texture。
fbo还有一个:Framebuffer completeness status,这个状态表明本fbo是否可以用来接受渲染结果。
注意:添加到一个fbo中attachment点的各个rbo或纹理才尺寸必须一致。
rbo的创建:
glGenRenderbuffers //得到一堆没有使用的rbo的名字
glDeleteRenderbuffers //删除rbo
glBindRenderbuffer //生成rbo,可以不调用glGenRenderbuffers生成未使用的rbo名字,
//但不推荐这么做。
glRenderbufferStorage(GLenum target,GLenum internalformat,
GLsizei width, GLsizei height)
//指定rbo的格式,申请存储空间。
//可以在rbo添加到fbo的绑定点之前或者之后调用这个函数
//但必须在使用fbo接受渲染结果之前调用这个函数。
GLint maxRenderbufferSize;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderbufferSize);//得到可以的最大的rbo大小。
fbo创建:
glGenFramebuffers
glDeleteFramebuffers
glBindFrameBuffer 一绑定fbo,这个fbo就作为渲染环境的当前 fbo来使用了,也就是
会渲染到这个fbo了。
glFramebufferRenderbuffer();
glFramebufferTexture2D();
如果一张纹理被添加到fbo,但在渲染的时候,这个纹理又被某个模型使用,
这样是会导致glDrawElement,glDrawArray失败。所以要注意避免这种情况。
检测fbo的完整性:
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
返回值:
GL_FRAMEBUFFER_COMPLETE
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 某个必要的attachment点绑定了无效的纹理或rbo
GL_FRAMEBUFFER_MISSING_ATTACHMENT 所有的attachment point都是0
GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 各个attachment之间的尺寸不匹配
GL_FRAMEBUFFER_INCOMPLETE_FORMATS 某个attachment的Internal format不能用于渲染。
GL_FRAMEBUFFER_UNSUPPORTED 三个attachment的组合的结果internal formats是不可渲染的。
窗口系统的surface可以支持多重采样,可以有多重采样缓存。fbo不支持多重采样缓存attachment。
关于提升渲染性能的建议:
频繁的在自己创建的fbo和窗口系统创建的vbo之间切换,比较影响性能。
不要在每一帧都去创建,销毁fbo,vbo对象。要一次创建多次使用。
如果一个纹理attach到一个fbo的attachment point,就要尽量避免调用glTexImage2D或glTexSubImage2D
glCopyTexImage2D等去修改纹理的值。