OpenGL 之 帧缓冲 使用实践

帧缓冲(Framebuffer Object),简称 FBO,在渲染绘制中, 图像最终都是绘制到 FBO 上的,一般都是默认的 FBO 上,也就是我们的屏幕。

除此之外,还可以创建自己的 FBO,用来作为绘制的载体,当在自己的 FBO 上绘制好了之后,可以再把绘制内容显示到屏幕上,实现一个双缓冲的绘制。

FBO 实际上是由颜色附件、深度附件、模板附件组成的,作为着色器各方面(一般包括颜色、深度、深度值)绘制结果存储的逻辑对象。

渲染缓冲(Renderbuffer Object),简称 RBO,由应用程序分配的 2D 图像缓冲区,可以用于分配和存储 深度模板 值,也可以用作 FBO 的 深度 或者 模板 附件,另外,纹理也可以作为 FBO 的颜色和深度附件。

帧缓冲与渲染缓冲和纹理的关系如下:

image

使用概述

帧缓冲的使用,首先就创建对应的帧缓冲对象,然后给它添加对应的附件,比如颜色附件或者深度附件等。

接着就是切换到帧缓冲渲染,在帧缓冲中进行绘制,此时绘制的内容都是记录在上一步添加的颜色附件或者深度附件上了。

然后切换到屏幕的缓冲区,这时可以把帧缓冲中记录的颜色或者深度信息取出来,再把他们绘制到屏幕上。

帧缓冲的使用看似很简单,但是用处却很普遍,使用帧缓冲可以在一些相机应用中做美颜处理、滤镜处理,也可以用来作贴纸等等效果。

使用步骤

创建 FBO

按照上面的步骤,首先是创建 FBO 。

        int[] framebuffers = new int[1];
        GLES20.glGenFramebuffers(1, framebuffers, 0);

和 OpenGL 中创建的大多对象相同,都是通过一个 int 型对象来表示的。

接下来就可以给这个 FBO 添加一些附件了。

绑定纹理

// 把纹理绑定到颜色附件
GLES20.glFramebufferTexture2D(
    GLES20.GL_FRAMEBUFFER, 
    GLES20.GL_COLOR_ATTACHMENT0, // 作为颜色附件
    GLES20.GL_TEXTURE_2D, 
    fboTextureId, 
    0);

通过 glFramebufferTexture2D 函数可以将纹理绑定到 FBO 上作为附件,在绑定时有多种附件选项可以选择。

  • GL_COLOR_ATTACHMENT0
    • 颜色附件
  • GL_DEPTH_ATTACHMENT
    • 深度附件
  • GL_STENCIL_ATTACHMENT
    • 模板附件

当然作为纹理,只有颜色和深度两种可以选择。

如果是使用 OpenGL 3.x 版本,在绑定 FBO 时,还可以选择是绑定只读还是只写的 FBO。

  • GL_READ_FRAMEBUFFER
    • 只读的 FBO
  • GL_DRAW_FRAMEBUFFER
    • 只写的 FBO

如果是使用 GL_FRAMEBUFFER 的话,那么读写皆可以。

绑定渲染缓冲

除了纹理之外,还可以绑定到渲染缓冲。

首先还是创建一个渲染缓冲对象:

        int[] renderbuffers = new int[1];
        GLES20.glGenRenderbuffers(1, renderbuffers, 0);

之后,要绑定到当前的渲染缓冲对象,并初始化渲染缓冲对象的数据存储,再把它添加到 FBO 上。

// 绑定到当前渲染缓冲对象
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderbufferId);
// 初始化渲染数据存储
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_ATTACHMENT, width, height);
// 将渲染缓冲添加到 FBO 上
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renderbufferId);

绑定渲染缓冲对象,并且初始化数据存储这一步有点类似于创建纹理并且初始化的操作。

        // 绑定纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        // 初始化纹理数据
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height,
                0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);

渲染

在渲染时,先渲染到 FBO 上,在渲染到屏幕上。

首先要切换到 FBO 进行渲染:

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);

如果 fboId 参数为 0 ,则代表切换到默认的屏幕上进行绘制。

此时就可以进行正常的绘制,由添加的附件去记录绘制的信息。

// 加载纹理
int textureId = TextureHelper.loadTexture(context, R.drawable.lgq);
// 将纹理绘制到 FBO 上
mTextureRect.drawSelf(textureId);

在 FBO 上绘制一张纹理贴图,此时 FBO 所绑定的颜色附件,会记录下纹理贴图的所有颜色内容。

也就是说,FBO 所绑定的纹理作为颜色附件,此时它已经被渲染上了颜色,而这个颜色就是我们绘制的内容,那么接下来就可以使用 FBO 绑定的纹理继续用来绘制。

        // 切换到屏幕的缓冲区
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        // 使用 FBO 所绑定的纹理进行绘制
        mTextureRect.drawSelf(fboTextureId);

切换到屏幕的缓冲区后,直接使用 FBO 绑定的纹理进行绘制,此时看到的效果和未使用 FBO 是相同的。

但是内部的绘制就是完全不一样了。

文章中具体代码部分,可以参考我的 Github 项目,欢迎 Star 。

https://github.com/glumes/AndroidOpenGLTutorial

参考

  1. https://blog.csdn.net/cauchyweierstrass/article/details/53166940
  2. 《OpenGL ES 3.x 游戏开发下卷》

一起交流学习,答疑解惑,有问题,我们星球见~~~


图形/图像/音视频交流

如果你也对 OpenGL 感兴趣,欢迎关注微信公众号:【纸上浅谈】,获得最新文章推送~~~

扫码关注
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • 版本记录 前言 OpenGL 图形库项目中一直也没用过,最近也想学着使用这个图形库,感觉还是很有意思,也就自然想着...
    刀客传奇阅读 13,573评论 1 13
  • 到目前为止,我们使用了几种不同类型的屏幕缓冲:用于写入颜色值的颜色缓冲,用于写入深度信息的深度缓冲,以及允许我们基...
    IceMJ阅读 13,473评论 3 29
  • 绘制到其他渲染目的地 Framebuffer对象是渲染命令的目标。当您创建一个framebuffer对象时,您可以...
    孙健会员阅读 1,187评论 0 3
  • 帧缓冲(Framebuffer),由颜色缓冲,深度缓冲,模板缓冲结合,被存储于内存中。 通过帧缓冲可以将你的场景渲...
    龙遁流阅读 2,759评论 0 2
  • 呼的一声,弯刀当头罩下。 只听后面嘤咛一声,段文恍惚间感觉似曾听见过,急忙收住刀势但已不及,但闻铛的一声,弯刀砍在...
    withocean01阅读 672评论 0 0