OpenGL ES 3.0 帧缓冲区对象基础知识
最近在帧缓冲区对象这里卡了一下,不过前面已经了解了相关的OpenGL ES的知识,现在再去了解就感觉轻松多了。现在就进行总结。
基础知识
我们知道,在应用程序调用任何的OpenGL ES命令之前,需要首先创建一个渲染上下文和绘图表面,并使之成为现行上下文和表面,之前在渲染的时候,其实一直使用的是原生窗口系统(比如EAGL,GLFW)提供的渲染上下文和绘图表面(即帧缓冲区)。
一般情况下,我们只需要系统提供的帧缓冲区作为绘图表面,但是又有些特殊情况,比如阴影贴图、动态反射、处理后特效等需要渲染到纹理(Render To Texture/RTT)操作的,如果使用系统提供的帧缓冲区,效率会比较低低下。
对于系统提供的帧缓冲区,如果要实现RTT,有下面两种方式:
- 直接将帧缓冲区的对应区域赋值到纹理来实现RTT。借助glCopyTexImage2D/glCopyTexSubImage2D来从帧缓冲区复制颜色数据到纹理缓冲区,因为需要复制数据,所以操作比较慢,而且受限于EGLSurface的宽高尺寸,纹理的尺寸只能小于等于帧缓冲区尺寸大小。
- 使用连接到纹理的pbuffer来实现RTT。窗口系统提供的EGLSurface必须连接到EGLContext,但是pbuffer和EGLSurface可能需要不同的EGLContext,这样实现可能效率低。而且,在窗口系统提供的EGLSurface之间转换可能需要清除所有切换之前渲染的图像,这会造成CPU的闲置,这种情况下建议不要使用,因为EGLSurface和EGLContext切换相关的开销很大。
如果应用程序只在屏幕上的表面绘图,则窗口系统提供的帧缓冲区通常很高效。但是很多应用程序需要你渲染到纹理,使用窗口提供的不太理想,因此需要自定义自己的帧缓冲区。
帧缓冲区对象API支持以下操作:
- 仅使用OpenGL ES命令创建帧缓冲区对象。
- 在单一EGL上下文中创建和使用多个帧缓冲区对象。也就是说,不需要每个帧缓冲区都有一个渲染上下文。
- 创建屏幕外颜色,深度或者模版渲染缓冲区和纹理,并将它们连接到帧缓冲区对象。
- 在多个帧缓冲区之间共享颜色、深度或者模版缓冲区。
- 将纹理直接连接到帧缓冲区作为颜色或者深度,从而避免了进行复制操作的必要。
- 在帧缓冲区之间复制并使帧缓冲区内容失效。
帧缓冲区对象是一组颜色、深度和模版纹理或者渲染目标,和默认的帧缓冲区一样,自定义的帧缓冲区也包括颜色缓冲区、深度和模版缓冲区,这些逻辑上的缓冲区在FBO中称之为可附加的图像,它们是可以附加到FBO的二维像素数组。
FBO包含两种类型的附加图像,纹理图像和渲染缓冲区图像。附加纹理时,OpenGL渲染到这个纹理图像,在着色器中可以访问到这个纹理对象;附加到渲染缓冲区时,OpenGL执行离屏渲染。
但是需要注意的地方是,FBO可以附加多个缓冲区,而且可以灵活的在缓冲区进行切换,FBO中包含一个以上的颜色附加点,各种2D图像可以连接到帧缓冲区对象中的颜色附加点,但是只有一个深度和模版附加点。如下图:


使用帧缓冲区对象
创建的过程和创建VBO是类似的。
void glGenFramebuffers(GLsizei n, GLuint* ids)
void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
void glBindFramebuffer(GLenum target, GLuint id)
这里的对象类型是指与附着点相关的对象的类型,如果要连接一个渲染缓冲区对象,则类型可以是GL_RENDERBUFFER,如果连接的是一个纹理对象,那么类型可以是GL_TEXTURE,但是默认值是GL_NONE。
使用渲染缓冲区对象
void glGenRenderbuffers(GLsizei n, GLuint* ids)
void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
void glBindRenderbuffer(GLenum target, GLuint id)
一旦绑定渲染缓冲区对象,就可以指定保存在渲染缓冲区对象中的图像大小和格式。
void glRenderbufferStorage(GLenum target,
GLenum internalFormat, GLsizei width, GLsizei height)
void glGetRenderbufferParameteriv(GLenum target, GLenum param, GLint* value)
附着
其中颜色附着可以分为渲染缓冲区附着或者纹理附着。
glFramebufferTexture2D(GLenum target,GLenum attachmentPoint,GLenum textureTarget,GLuint textureId, GLint level)
void glFramebufferRenderbuffer(GLenum target,GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbufferId)
其实还可以连接3D纹理的一个图像作为帧缓冲区附着。
void glFramebufferTextureLayer(GLenum target,GLenum attachment, GLuint texture, GLint level, GLint layer);
检查帧缓冲区完整性
帧缓冲区对象必须定义为完整的才能够用作渲染目标。
其中帧缓冲区对象被视为完整的规则如下:
- 确保颜色、深度和模版附着有效;帧缓冲区至少有一个有效的附着,如果没有任何附着,那么帧缓冲区则是不完整的,因为没有可以绘制或者读取的区域。
- 与帧缓冲区对象相关的有效附着必须有相同的宽度和高度。
- 如果存在深度和模版附着,则它们必须是相同的宽度和高度。
- 所有渲染缓冲区附着的GL_RENDERBUFFER_SAMPLES值都相同。如果附着是渲染缓冲区和纹理的结合,则GL_RENDERBUFFER_SAMPLES的值为0。
glCheckFramebufferStatus命令可用于验证帧缓冲区对象是否完整,其返回的是一个枚举,是否完整。
GLenum glCheckFramebufferStatus( GLenum target);
GLenum glCheckNamedFramebufferStatus(GLuint framebuffer,GLenum target);
帧缓冲区位块传送
帧缓冲区位块传送可以高效的将一个矩形区域的像素值从一个帧缓冲区(读帧缓冲区)复制到另一个帧缓冲区(绘图帧缓冲区)。帧缓冲区位块传送的关键应用之一是将一个多重采样渲染缓冲区解析为一个纹理(用一个帧缓冲区对象,纹理绑定为它的颜色附着)。
void glBlitFramebuffer( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
这个函数是从es 3.0才开始支持。
帧缓冲区失效
帧缓冲区失效为应用程序提供了一个通知驱动程序不再需要帧缓冲区内容的机制。因为可以通知无效,所以这可以使得驱动程序采取多种优化步骤:1.跳过在块状渲染(TBR)架构中为了进一步渲染到帧缓冲区而做的不必要的图块内容修复;2.跳过多GPU系统中GPU之间不必要的数据复制;3.跳过某些实现中为了改进性能而对特定缓存的刷新。这种功能对于许多应用程序中实现峰值性能很重要,特别是那些执行大量屏幕外渲染的应用。
这个函数在es 3.0中才会实现。
我们需要先了解TBR GPU中的设计,才能知道帧缓冲区失效对于GPU的重要性。TBR GPU常常部署在移动设备上,以最小化GPU和系统内存之间数据传输量,从而减少最大的电力消耗者之一,内存带宽;这通过添加能够保存少量像素数据的芯片内建快速存储器来实现,然后,帧缓冲区被区分为许多个图块,对于每个图块,图元被渲染到芯片内建的存储器中,然后结果在完成时被复制到系统内存。因为每个像素的最少量数据(最终像素结果)被复制到系统内存,所以这种方法节约了GPU和系统内存之间的内存带宽。
有了帧缓冲区失效机制,GPU就可以删除不再需要的帧缓冲区内容,以减少每个帧保留的内容数量,此外,如果图块数据不再有效,GPU还可以消除从芯片内建存储器到系统内存不必要的数据传输,因为GPU和系统内存之间内存带宽需求明显降低,所以电力消耗随之下降,性能则得到改善。
其中glInvalidateFramebuffer和glInvalidateSubFramebuffer命令用于使整个帧缓冲区或者帧缓冲区的像素子区域失效。
void glInvalidateFramebuffer( GLenum target, GLsizei numAttachments, const GLenum *attachments);
void glInvalidateSubFramebuffer( GLenum target, GLsizei numAttachments, const GLenum * attachments, GLint x, GLint y, GLint width, GLint height);
性能提示和技巧
在使用帧缓冲区对象时应该要认真考虑的性能提示:
- 避免频繁地在渲染到窗口系统提供的帧缓冲区和渲染到帧缓冲区对象之间切换。
- 不要逐帧创建和删除帧缓冲区和帧缓冲区对象(或者任何其他大型数据对象)。
- 尝试避免修改用作渲染图标的帧缓冲区对象附着的纹理,也就是说当指定纹理附着到帧缓冲区对象上以后,不要再进行修改(使用glTexImage2D、glTexSubImage2D、glCopyTexImage2D等)。
- 如果整个纹理图像将被渲染,则将glTexImage2D和glTexImage3D中的pixel参数设置为NULL,因为原始数据不会被使用。如果你希望图像包含任何预先定义的像素值,那么在绘制到纹理之前使用glInvalidateFramebuffer清除纹理图像。
- 尽可能共享帧缓冲区对象使用的用作附着的深度和模版渲染缓冲区,以保证内存占用需求最小,但是需要注意的是,因为帧缓冲区的宽度和高度必须相同。
OpenGL ES 3.0 帧缓冲区对象基础知识的更多相关文章
- OpenGL ES 3.0 顶点缓冲区VBO使用
一般情况下数据都是有CPU从RAM取数据 然后传给GPU去处理,相对于GPU速度要慢一些. 使用VBO技术 可以把数据存储到GPU的内存空间中,这样GPU可以直接从GPU的内存中取得数据进行处理 速度 ...
- OpenGL ES 3.0之Fragment buffer objects(FBO)详解 (转)
http://www.cnblogs.com/salam/p/4957250.html 片段操作图 这篇文章将介绍从写入帧缓冲和读取帧缓冲的方式. Buffers(缓冲) OpenGL ES支持三种缓 ...
- OpenGL ES 3.0之Fragment buffer objects(FBO)详解(二)
我们可以使用帧缓冲对象来实现离屏渲染.帧缓冲对象支持下列操作 1.只使用OpenGL ES 函数创建帧缓冲区对象. 2.使用EGL context创建多个FBO. 3.创建离屏颜色.深度.模板渲染缓冲 ...
- [置顶] 使用Android OpenGL ES 2.0绘图之五:添加运动
传送门 ☞ 系统架构设计 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 传送门 ☞ GoF23种设计模式 ☞ 转载请注明 ☞ http://blog.csd ...
- OpenGL ES 3.0 基础知识
首先要了解OpenGL的图形管线有哪些内容,再分别去了解其中的相关的关系: 管线分别包括了顶点缓冲区/数组对象,定点着色器,纹理,片段着色器,变换反馈,图元装配,光栅化,逐片段操作,帧缓冲区.其中顶点 ...
- OpenGL ES 3.0之VertexAttributes,Vertex Arrays,and Buffer Objects(九)
顶点数据,也称为顶点属性,指每一个顶点数据.指能被用来描述每个顶点的数据,或能被所有顶点使用的常量值.例如你想绘制一个具有颜色的立方体三角形.你指定一个恒定的值用于三角形的所有三个顶点颜色.但三角形的 ...
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- OpenGL ES 2.0 渲染管线 学习笔记
图中展示整个OpenGL ES 2.0可编程管线 图中Vertex Shader和Fragment Shader 是可编程管线: Vertex Array/Buffer objects 顶点数据来源, ...
- 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
随机推荐
- listen系统调用
/* * Perform a listen. Basically, we allow the protocol to do anything * necessary for a listen, and ...
- 玩玩 Nginx 1----- Nginx + ngx_lua安装测试【CentOs下】
最近打算搞搞nginx,扒着各位先驱的文章自己进行测试下,中间过程也是错误不断,记录一下,以备使用. nginx的安装挺简单的,主要还是研究下一些第三方的模块,首先想试下初始化 ...
- 数据库-mysql视图
视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用 一:创建视图 create view view ...
- sem_open中信号量命名
问题: sem_open will failed with "No such file or directory" 解释1: 这是由于在Linux内核中,创建信号量的默认路径是 ...
- 使用文本用户界面(NMTUI)进行网络配置
NetworkManager 文本用户界面(TUI)工具 nmtui 可提供一个文本界面配置由 NetworkManager 控制的网络.该工具包含在 NetworkManager-tui 子软件包中 ...
- gtk+学习笔记(五)
今天继续做的是昨天那个界面对的优化,直接贴下代码, void click_radio(GtkWidget *widget,gpointer *data) { 3 GtkWidget *dialog; ...
- HTML5元素1
文档和元数据元素 元素 说明 类型 HTML5与其他的变化 base 设置相对URL的基础 元数据 无变化 body 表示HTML文档的内容 无 有变化 DOCTYPE 表示HTML文档的开始 无 有 ...
- https页面打不开
https://blog.csdn.net/leedaning/article/details/71552625
- javascript输入验证数字方法,适合充值时输入正整数验证
说明:用于验证正整数的输入,不允许输入其他字符. html: <input type="text" id="sell_jobNum" name=" ...
- Gitlab-通过API管理项目
Gitlab有一个非常强大的API,几乎可以通过API管理在Gitlab服务器中的所有项目. 在这里我们只是测试终端点的API, 因此我们需要一个程序来进行测试 .在这里我使用的是针对Google浏览 ...