作用

FrameBuffer Object,也称FBO,离屏渲染,可以摆脱屏幕的束缚,在后台做图像处理。

理解

FrameBuffer和Texture绑定,FrameBuffer犹如画板,而Texture犹如画纸,我们在上面画东西,画完后,我们可以拿Texture去绘制到其他地方上面。

(本文重点:这个是我个人对FBO的理解,也是帮助我去使用它的方式。如果有更好的理解方式,可以留言沟通。)

代码

本章案例效果是在屏幕外绘制一张图片,并保存到本地。

由于GL运行需要EGL环境,而GLSurfaceView已经帮我们构建了这样的一个环境,所以我们此次也是在GLSurfaceView上运行,但是不绘制到屏幕上。

案例为试验效果,只绘制一帧,所以就放到onDrawFrame上运行,读者之后可以根据自己的需求,处理好相关的生命周期。

public void onDrawFrame(GL10 glUnused) {

GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

// 1. 创建FrameBuffer、纹理对象

createEnv();

// 2. 配置FrameBuffer相关的绘制存储信息,并且绑定到当前的绘制环境上

bindFrameBufferInfo();

// 3. 更新视图区域

GLES20.glViewport(0, 0, mTextureBean.getWidth(), mTextureBean.getHeight());

// 4. 绘制图片

drawTexture();

// 5. 读取当前画面上的像素信息

readPixels(0, 0, mTextureBean.getWidth(), mTextureBean.getHeight());

// 6. 解绑FrameBuffer

unbindFrameBufferInfo();

// 7. 删除FrameBuffer、纹理对象

deleteEnv();

}

以上就是关键代码,相比之前其他章节,这里多出了1、2、6、7这几个关键步骤。

步骤1. 创建FrameBuffer、纹理对象

private int[] mFrameBuffer = new int[1];

private int[] mTexture = new int[1];

private void createEnv() {

// 1. 创建FrameBuffer

GLES20.glGenFramebuffers(1, mFrameBuffer, 0);

// 2.1 生成纹理对象

GLES20.glGenTextures(1, mTexture, 0);

// 2.2 绑定纹理对象

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[0]);

// 2.3 设置纹理对象的相关信息:颜色模式、大小

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,

mTextureBean.getWidth(), mTextureBean.getHeight(),

0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

// 2.4 纹理过滤参数设置

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

// 2.5 解绑当前纹理,避免后续无关的操作影响了纹理内容

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

}

创建纹理和之前的没有差别,而创建Framebuffer也很简单。

步骤2. 配置FrameBuffer相关的绘制存储信息,并且绑定到当前的绘制环境上

private void bindFrameBufferInfo() {

// 1. 绑定FrameBuffer到当前的绘制环境上

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]);

// 2. 将纹理对象挂载到FrameBuffer上,存储颜色信息

GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,

GLES20.GL_TEXTURE_2D, mTexture[0], 0);

}

这里先将FrameBuffer绑定到当前的绘制环境上,所以,在没解绑之前,所有的GL图形绘制操作,都不是直接绘制到屏幕上,而是绘制到这个FrameBuffer上!

若想要解绑,想直接绘制到屏幕上,则可以通过GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);实现。

第二步是将FrameBuffer和纹理对象相关联,纹理存储绘制到FrameBuffer上的颜色信息,代码也很简单。

步骤6. 解绑FrameBuffer

private void unbindFrameBufferInfo() {

// 解绑FrameBuffer

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

}

解绑,之后的绘制操作都是直接绘制到屏幕上。

步骤7. 删除FrameBuffer、纹理对象

private void deleteEnv() {

GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0);

GLES20.glDeleteTextures(1, mTexture, 0);

}

注意

FrameBuffer每次绘制都会得到一个水平镜像翻转的视图,要处理这个问题,可以在绘制的时候添加一个翻转矩阵,或者,用FrameBuffer绘制2次。

总结

本章使用FrameBuffer实现了离屏渲染,并且将FrameBuffer上的绘制信息保存成Bitmap到本地(此处省略,详细可以看GitHub工程),而FrameBuffer除了这个作用外,还可以将离屏渲染好的图片再绘制到屏幕上,而不用绘制到本地,毕竟我们绘制后得到一个Texture,那就有发挥的空间。比如我们要做的效果是屏幕上画一个背景,背景上有朵花,一共2张图,但背景要做滤镜处理,而花不用,那么,我们可以将背景通过FrameBuffer去做滤镜处理,然后得到一个纹理,直接绘制到屏幕上,而花直接绘制,那么就得到想要的效果了。具体留给读者作为练习题。

后记

该篇文章是差不多半年前就写好的文章,不过觉得写得比较简陋,缺少一些图片来生动形象地去描述这个概念,也怕自己的局限误导了读者。不过由于有读者好奇追问,所以就勉强放上来。文中若有疏漏、误导,请指出。

阅读资料

其他

本系列课程所有相关代码请参考我的GitHub项目⭐GLStudio⭐,喜欢的请给个小星星。

android 离屏渲染 简单书,Android OpenGL ES 8.FrameBuffer离屏渲染相关推荐

  1. SDL2源码分析之OpenGL ES在windows上的渲染过程

    SDL2源码分析之OpenGL ES在windows上的渲染过程 更新于2018年11月4日. 更新于2018年11月21日. ffmpeg + SDL2实现的简易播放器 ffmpeg和SDL非常强大 ...

  2. Android技术应用实验指导书,Android应用开发实验指导书

    第 1 页手机应用开发实验指导书西南科技大学计算机科学与技术学院2015.11第 2 页目录手机应用开发 .1实验指导书 .1实验一:搭建 Android开发平台和创建 HelloWorld程序 .- ...

  3. android 流星动画,超简单的android 流星雨动画 流星动画

    1.直接看效果 2.布局文件 xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http: ...

  4. OpenGL ES之基本简介和渲染流程

    简介 OpenGL ES (OpenGL for Embedded Systems) 是以⼿持和嵌入式为目标的高级3D图形应用程序编程接口(API). OpenGL ES是目前智能手机中占据统治地位的 ...

  5. android漫画app代码,漫画书Android客户端 – ComicApp

    漫画书 1.平台:Android客户端(后期完善IOS端) 2.开发框架:React Native react-redux react-thunk 3.开发工具:Vs Code 1.8 1.项目架构 ...

  6. Android动态日志,一个简单的Android日志类

    Android自带的日志类不支持显示文件名和行号,调试时很不方便.而第三方日志库往往又太重.所以自己对Android自带的日志类做了一个简单的封装,主要是调试时使用,不考虑日志丢失和性能问题.日志的输 ...

  7. android沉浸式模式简书,Android 沉浸式模式与常见状态栏和导航栏效果

    Android沉浸式模式 官方称沉浸式状态栏为沉浸式模式. 什么是沉浸式? 沉浸式就是让人专注当前的(由设计者营造)情境下感到愉悦和满足,而忘记真实的情境. 什么是Android中的沉浸式? 当启用该 ...

  8. android源码编译 简书,android学习笔记之源码编译

    编译环境 1.需要Ubuntu 64bit,建议Ubuntu14.04 64-bit 2.安装openJDK7 $ sudo apt-get update $ sudo apt-get install ...

  9. android+包+反编译,简单的Android之apk包反编译方法

    网上相关的文章一大堆了,我只是总结下自己的反编译方法和工具 工具下载地址: 下载上面的三个工具的压缩包 Apktool_v1.5.1_CHS_By_b-sf.rar dex2jar.zip jd-gu ...

最新文章

  1. SQL Server-创建表格、各种约束条件
  2. tcpdump抓包命令_tcpdump实战
  3. 重构——30以类取代类型码(Replace Type Code with Class)
  4. 深度学习导论(5)手写数字识别问题步骤
  5. java国家电网面试试题_国家电网笔试面试相关
  6. Reporting Services Catalog Database File Existence error during installing SQL Server 2008 R2
  7. 从华住遭遇“抄袭” 看酒店行业互联网发展现状
  8. 联想年报有看头:供应链展现韧性,PC迎来新机遇
  9. ZBrush中的法线贴图你知道吗?
  10. 如何在 5 分钟内成为游戏引擎的行家
  11. 基于JNA(Java Native Access)实现RFID单卡、多卡读取以及写入。
  12. Linux wifi hostpad,将你的电脑变身无线路由wifi host, ipad/ipod/手机一起来无线互联吧...
  13. 从云计算到固态硬盘 颠覆性技术成熟度分析
  14. linux修改配置文件configure,./configure 的配置和用法
  15. 计算机闪存大小,电脑内存大小有什么区别
  16. 海思平台ISP调试经验
  17. Exception in thread main java.lang.NoSuchMethodError: scala.Predef$.ArrowAssoc(Ljava/lang/Object;)
  18. 程序猿生存指南-16 农村青年
  19. Flutter Scaffold
  20. 麻将胡牌算法思路(任意赖子)

热门文章

  1. phpstudy mysql 版本_phpStudy中升级MySQL版本到5.7.17的方法步骤
  2. python以垂直方式输出hello world_python3提问:垂直输出Hello World,全部代码不超过2行....
  3. 美国教授描述未来学校,将颠覆现有教育模式
  4. 一次阿里巴巴面试……
  5. 8万级自动挡智能SUV,舒适好开是亮点,众泰T600Coupe要逆天?
  6. 为何美洲蝉中意17这个质数?
  7. linux 打开上一级目录,linux开机启动过程、PATH、过滤一级目录、cd的参数、ls -lrt、命令切割日志...
  8. 计算机考试演示文稿模板,2018职称计算机考试PowerPoint习题10
  9. PHP实现RPC(简版)
  10. #pragma code_seg(INIT)/code_seg(PAGE)