【OpenGL ES】帧缓冲区对象FBO

时间:2021-07-27 02:58:47

1、FBO

使用OpenGL ES,一般要通过EGL来配置本地窗口系统,关于EGL的介绍可参照“【OpenGL ES】EGL简介”http://blog.csdn.net/ieearth/article/details/71180457。默认情况下,OpenGL ES使用窗口系统提供的帧缓冲区作为绘图表面,但是许多应用程序需要渲染到纹理,可行的方案是使用glCopyTexImage2D和glCopyTexSubImage2D从帧缓冲区拷贝到纹理,但是影响性能,而且只有在纹理的尺寸小于等于帧缓冲区的尺寸时才有效,另一种方案是使用pbuffer,但是与上下文Context和窗口系统提供的可绘制表面Surface的切换开销也很大,所以,引入了帧缓冲区对象FBO来解决这个问题。对于渲染的纹理的用例,应该将一个纹理对象连接到FBO,例如,渲染到一个用作颜色纹理的颜色缓冲区,以及渲染到用作阴影的深度纹理的深度缓冲区。

渲染缓冲区对象,是一个由应用程序分配的2D图像缓冲区。渲染缓冲区可以用于分配和存储颜色、深度或者模板值,可以用作FBO中的颜色、深度或者模板附着。渲染缓冲区类似于屏幕外的窗口系统提供的可绘制表面如pbuffer,但是渲染缓冲区不能直接用作GL纹理。FBO是一组颜色、深度和模板纹理或者渲染目标,一个FBO中只能有一个颜色、深度和模板附着。各种2D图像可以连接到FBO中的颜色附着点,这些附着点包括一个渲染缓冲区对象,它保存颜色值、2D纹理或者立方图面的mip级别、2D数组纹理的层次甚至3D纹理中的一个2D切片的mip级别。同样,包含深度值的各种2D图像可以连接到FBO的深度附着点,这些附着点包括渲染缓冲区、2D纹理的mip级别或者保存深度值的一个立方图。最后,可以连接到FBO模板附着点的唯一2D图像是保存模板值的渲染缓冲区对象。

选择渲染缓冲区代替纹理,性能可能更好,而且渲染缓冲区支持多重采样。

FBO与窗口系统提供的可绘制表面相比,像素归属测试时FBO始终成功,窗口系统则要判断像素是否属于当前OpenGL ES上下文;对于缓冲来说,FBO只支持单缓冲附着,窗口系统一般支持双缓冲表面;FBO可以实现帧缓冲区之间深度和模板缓冲区的共享,而窗口系统提供的帧缓冲区则不能实现这一功能,

2、使用渲染缓冲区对象

void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers);
void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers);
GLboolean glIsRenderbuffer(GLuint renderbuffer);
void glBindRenderbuffer(GLenum target, GLuint renderbuffer);
void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);

创建渲染缓冲区对象使用glGenRenderbuffers,删除渲染缓冲区对象使用glDeleteRenderbuffers。判断是否属于渲染缓冲区对象使用glIsRenderbuffer。绑定渲染缓冲区对象使用glBindRenderbuffer。指定渲染缓冲区对象中的图像格式和大小使用glRenderbufferStorage或者是多重采样版本的glRenderbufferStorageMultisample。

3、使用FBO

void glGenFramebuffers(GLsizei n, GLuint *framebuffers);
void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
GLboolean glIsFramebuffer(GLuint framebuffer);
void glBindFramebuffer (GLenum target, GLuint framebuffer);
void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
void glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
GLenum glCheckFramebufferStatus(GLenum target);
void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
void glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);

创建FBO使用glGenFramebuffers,删除FBO使用glDeleteFramebuffers。判断是否属于FBO使用glIsFramebuffer。绑定FBO使用glBindFramebuffer。连接渲染缓冲区对象作为FBO附着点使用glFramebufferRenderbuffer,将2D纹理的某个mip级别或者立方图面连接到FBO附着点使用glFramebufferTexture2D,将3D纹理的一个2D切片或者2D纹理数组的一个级别连接到FBO附着点使用glFramebufferTextureLayer。检查FBO的完整性使用glCheckFramebufferStatus,如果FBO不完整,后续对FBO的操作都将失败。通知驱动程序不再需要帧缓冲区的内容即使得帧缓冲区失效时使用glInvalidateFramebuffer或glInvalidateSubFramebuffer,有助于提升程序性能,降低功耗。glReadPixels从颜色缓冲区读取像素,并在一个用户分配的缓冲区中返回它们,读取的颜色缓冲区是窗口系统提供的帧缓冲区分配的颜色缓冲区,或者是当前绑定的FBO的颜色附着。

4、Blit

void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);

Blit,位块传输,是一个重要的技术,可以高效地将一个矩形区域的像素从一个读帧缓冲区复制到另一个绘图缓冲区。帧缓冲区Blit的关键应用之一是将一个多重采样缓冲区解析为一个纹理,也就是用纹理绑定为一个FBO的颜色附着。一个说明如何使用帧缓冲区Blit从FBO复制四个颜色缓冲区到默认帧缓冲区窗口的四个象限的例子请参照https://github.com/geminy/aidear/tree/master/graphics/mu/examples/opengles3/MRTs