OpenGLES帧缓冲

2024-05-04 03:32
文章标签 opengles 缓冲

本文主要是介绍OpenGLES帧缓冲,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://www.jianshu.com/p/78a64b8fb315

 

FBO

Frame Buffer object

为什么要用FBO

我们需要对纹理进行多次渲染采样时,而这些渲染采样是不需要展示给用户看的,所以我们就可以用一个单独的缓冲对象(离屏渲染)来存储我们的这几次渲染采样的结果,等处理完后才显示到窗口上

优势

提高渲染效率,避免闪屏,可以很方便的实现纹理共享等。

渲染方式

  1. 渲染到纹理(Texture)- 图像渲染
  2. 渲染到缓冲区(Render)- 深度测试和模板测试

FBO纹理的坐标系

FBO坐标系

渲染到纹理

工作流程

创建FBO的步骤:


//1. 创建FBO
int[] fbos = new int[1];
GLES20.glGenFramebuffers(1, fbos, 0);
fboId = fbos[0];//2. 绑定FBO
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//3. 创建FBO纹理
fboTextureId = createTexture();//4. 把纹理绑定到FBO
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D, fboTextureId, 0);//5. 设置FBO分配内存大小
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,bitmap.getWidth(), bitmap.getHeight(),0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);//6. 检测是否绑定从成功
if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)!= GLES20.GL_FRAMEBUFFER_COMPLETE) {Log.e("zzz", "glFramebufferTexture2D error");
}//7. 解绑纹理和FBO
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

使用FBO的步骤:

//1. 绑定fbo
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//2. FBO绘制
GLES20.glUseProgram(program);
//绑定渲染纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTextureId);
//...
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
//解绑fbo
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);//3. 根据绑定到fbo上的纹理id,渲染GLES20.glUseProgram(program);
//绑定渲染纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);//...

示例代码如下:

TexureRender.java


import android.content.Context;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;public class TexureRender implements EglSurfaceView.Renderer {private BitmapFboTexture bitmapFboTexture;private BitmapRenderTexture bitmapRenderTexture;public TexureRender(Context context) {bitmapFboTexture = new BitmapFboTexture(context);bitmapFboTexture.setBitmap(BitmapFactory.decodeResource(context.getResources(),R.mipmap.bg));bitmapRenderTexture = new BitmapRenderTexture(context);}@Overridepublic void onSurfaceCreated() {bitmapFboTexture.onSurfaceCreated();bitmapRenderTexture.onSurfaceCreated();}@Overridepublic void onSurfaceChanged(int width, int height) {//宽高GLES20.glViewport(0, 0, width, height);bitmapFboTexture.onSurfaceChanged(width, height);bitmapRenderTexture.onSurfaceChanged(width, height);}@Overridepublic void onDrawFrame() {//清空颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);//设置背景颜色GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//FBO处理bitmapFboTexture.draw();//通过FBO处理之后,拿到纹理id,然后渲染bitmapRenderTexture.draw(bitmapFboTexture.getFboTextureId());}
}

FBO处理类: BitmapFboTexture.java


import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;//纹理  根据坐标系映射
public class BitmapFboTexture {//顶点坐标static float vertexData[] = {   // in counterclockwise order:-1f, -1f, 0.0f, // bottom left1f, -1f, 0.0f, // bottom right-1f, 1f, 0.0f, // top left1f, 1f, 0.0f,  // top right};//正常纹理坐标  对应顶点坐标  与之映射
//    static float textureData[] = {   // in counterclockwise order:
//            0f, 1f, 0.0f, // bottom left
//            1f, 1f, 0.0f, // bottom right
//            0f, 0f, 0.0f, // top left
//            1f, 0f, 0.0f,  // top right
//    };//fbo 纹理坐标static float textureData[] = {   // in counterclockwise order:0f, 0f, 0.0f, // bottom left1f, 0f, 0.0f, // bottom right0f, 1f, 0.0f, // top left1f, 1f, 0.0f,  // top right};//每一次取点的时候取几个点static final int COORDS_PER_VERTEX = 3;private final int vertexCount = vertexData.length / COORDS_PER_VERTEX;//每一次取的总的点 大小private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertexprivate Context context;//位置private FloatBuffer vertexBuffer;//纹理private FloatBuffer textureBuffer;private int program;private int avPosition;//纹理位置private int afPosition;//需要渲染的纹理idprivate int imageTextureId;//fbo纹理idprivate int fboTextureId;//fbo Idprivate int fboId;private Bitmap bitmap;public void setBitmap(Bitmap bitmap) {this.bitmap = bitmap;}public BitmapFboTexture(Context context) {this.context = context;vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);vertexBuffer.position(0);textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(textureData);textureBuffer.position(0);}public void onSurfaceCreated() {String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);program = ShaderUtil.createProgram(vertexSource, fragmentSource);if (program > 0) {//获取顶点坐标字段avPosition = GLES20.glGetAttribLocation(program, "av_Position");//获取纹理坐标字段afPosition = GLES20.glGetAttribLocation(program, "af_Position");createFBO();imageTextureId = createImageTexture();}}public void draw() {//绑定fboGLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//使用程序GLES20.glUseProgram(program);//绑定渲染纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTextureId);GLES20.glEnableVertexAttribArray(avPosition);GLES20.glEnableVertexAttribArray(afPosition);//设置顶点位置值GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);//设置纹理位置值GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer);//绘制 GLES20.GL_TRIANGLE_STRIP:复用坐标GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);GLES20.glDisableVertexAttribArray(avPosition);GLES20.glDisableVertexAttribArray(afPosition);//解绑纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);//解绑fboGLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);}private void createFBO() {if (bitmap == null) {throw new IllegalArgumentException("bitmap is  null");}//1. 创建FBOint[] fbos = new int[1];GLES20.glGenFramebuffers(1, fbos, 0);fboId = fbos[0];//2. 绑定FBOGLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//3. 创建FBO纹理fboTextureId = createTexture();//4. 把纹理绑定到FBOGLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D, fboTextureId, 0);//5. 设置FBO分配内存大小GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(),0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);//6. 检测是否绑定从成功if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)!= GLES20.GL_FRAMEBUFFER_COMPLETE) {Log.e("zzz", "glFramebufferTexture2D error");}//7. 解绑纹理和FBOGLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);}private int createImageTexture() {int[] textureIds = new int[1];//创建纹理GLES20.glGenTextures(1, textureIds, 0);if (textureIds[0] == 0) {return 0;}//绑定纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);//环绕(超出纹理坐标范围)  (s==x t==y GL_REPEAT 重复)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//过滤(纹理像素映射到坐标点)  (缩小、放大:GL_LINEAR线性)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);//测试图片GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);//解绑纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);return textureIds[0];}private int createTexture() {int[] textureIds = new int[1];//创建纹理GLES20.glGenTextures(1, textureIds, 0);if (textureIds[0] == 0) {return 0;}//绑定纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);//环绕(超出纹理坐标范围)  (s==x t==y GL_REPEAT 重复)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//过滤(纹理像素映射到坐标点)  (缩小、放大:GL_LINEAR线性)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);return textureIds[0];}public int getFboTextureId() {return fboTextureId;}public void onSurfaceChanged(int width, int height) {}
}

渲染类:BitmapRenderTexture.java


import android.content.Context;
import android.opengl.GLES20;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;//纹理  根据坐标系映射
public class BitmapRenderTexture {//顶点坐标static float vertexData[] = {   // in counterclockwise order:-1f, -1f, 0.0f, // bottom left1f, -1f, 0.0f, // bottom right-1f, 1f, 0.0f, // top left1f, 1f, 0.0f,  // top right};//纹理坐标  对应顶点坐标  与之映射static float textureData[] = {   // in counterclockwise order:0f, 1f, 0.0f, // bottom left1f, 1f, 0.0f, // bottom right0f, 0f, 0.0f, // top left1f, 0f, 0.0f,  // top right};//每一次取点的时候取几个点static final int COORDS_PER_VERTEX = 3;private final int vertexCount = vertexData.length / COORDS_PER_VERTEX;//每一次取的总的点 大小private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertexprivate Context context;//位置private FloatBuffer vertexBuffer;//纹理private FloatBuffer textureBuffer;private int program;private int avPosition;//纹理位置private int afPosition;public BitmapRenderTexture(Context context) {this.context = context;vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);vertexBuffer.position(0);textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(textureData);textureBuffer.position(0);}public void onSurfaceCreated() {String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);program = ShaderUtil.createProgram(vertexSource, fragmentSource);if (program > 0) {//获取顶点坐标字段avPosition = GLES20.glGetAttribLocation(program, "av_Position");//获取纹理坐标字段afPosition = GLES20.glGetAttribLocation(program, "af_Position");}}public void draw(int textureId) {//使用程序GLES20.glUseProgram(program);//绑定渲染纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);GLES20.glEnableVertexAttribArray(avPosition);GLES20.glEnableVertexAttribArray(afPosition);//设置顶点位置值GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);//设置纹理位置值GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer);//绘制 GLES20.GL_TRIANGLE_STRIP:复用坐标GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);GLES20.glDisableVertexAttribArray(avPosition);GLES20.glDisableVertexAttribArray(afPosition);//解绑纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);}public void onSurfaceChanged(int width, int height) {GLES20.glViewport(0, 0, width, height);}
}

这篇关于OpenGLES帧缓冲的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/958253

相关文章

工作集、granule、缓冲区、缓冲池概念及关系?

工作集、granule、缓冲区、缓冲池概念及关系? granule:为了让内存在db_chache_size和shared_pool_size之间高效的移动,oracle在9i重构SGA,使用固定大小的内存块即为granule。这个参数就是为什么当你分配给shared pool值的时候,为什么有时候比你分配的值要大一点,但是granule的整数倍。 缓冲区:内存存放数据的地方,类似于数

图形API学习工程(8):使用顶点索引缓冲

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 目标 在《图形API学习工程(5):图形管线&顶点缓冲》中,实现了渲染出一个三角形。 他有三个顶点。但是考虑图形变得复杂些的情况,就假如是一个四边形吧,那就需要分解为两个三角形来渲染了,而每个三角形需要三个顶点,也就是说,共需要6个顶点数据。 然而,如上图所示,实际上顶点是有重复的:0和3重复

【大数据Java基础-JAVA IO 4】JAVA IO流 (四) 缓冲流的使用

packageatguigu.senior.day11.java;importorg.junit.Test;import java.io.*;/*** 处理流之一:缓冲流的使用 1.缓冲流: BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter 2.作用:提供流的读取、写入的速度 提高读写

Android OpenGLES开发:EGL环境搭建

努力,不是为了要感动谁,也不是要做给哪个人看,而是要让自己随时有能力跳出自己厌恶的圈子,并拥有选择的权利,用自己喜欢的方式过一生! EGL是什么? 谈到openGL开发我们就不得不说EGL,那EGL是什么呢?请看下图 官方听不懂解释 EGL(Embedded Graphic Library)是渲染API(如OpenGL ES)和本地窗口系统(native platform w

OpenGL双缓冲

1.双缓冲技术解决的问题 在计算机上的动画与实际的动画有些不同:实际的动画都是先画好了,播放的时候直接拿出来显示就行。计算机动画则是画一张,就拿出来一张,再画下一张,再拿出来。如果所需要绘制的图形很简单,那么这样也没什么问题。但一旦图形比较复杂,绘制需要的时间较长,问题就会变得突出。 让我们把计算机想象成一个画图比较快的人,假如他直接在屏幕上画图,而图形比较复杂,则有可能在他只画了某幅图的一半

双缓冲和单缓存的区别

双缓冲和单缓存的区别 编码时遇到glutInitDisplayMode(unsigned int mode) ;函数,主要作用是设置初始显示模式,其中有两个可用形参不甚理解。分别为GLUT_SINGLE,GLUT_DOUBLE。其中GLUT_SINGLE指定单缓存窗口,GLUT_DOUBLE指定双缓存窗口。 这里必须要搞明白双缓存窗口和单缓存窗口的区别。 单缓存窗口:实际上就是将所有的绘图指

Qt22双缓冲机制

Qt22双缓冲机制 知识点drawwidgetdrawwidget.hdrawwidget.cpp mainwindowmainwindow.hmainwindow.cpp main.cpp运行图 知识点 双缓冲就是在内存区申请一块缓存;然后显卡直接从这块内存读取数据.。 这样就不用鼠标边画,经过IO来读取这个环节; 鼠标驱动 — 内存缓冲区— 显卡 drawwidget d

【Redis】缓冲之Redis简介

** Redis简介 ** Redis是Remote Dictionary Server的缩写,它是由Salvator Sanfilippo编写的key-value存储结构,是一个使用ANSI编写,遵守BSD协议,支持网络、可基于内存也可以持久化的key-value的nosql数据库,并提供了多种语言的API,它允许缓冲的值(value)可以是字符串(string)、哈希(hash)、列表(

Direct9学习之--------------------------模板缓冲的应用

一.模板缓冲区: 板缓冲区(Stencil Buffer)与后台缓冲区大小相同,类似于深度缓冲区可以控制相似是否写入。 模板可以通过设置简单的参数及测试方法允许或者拒绝像素的写入。 利用模板缓冲技术可以实现阴影体 镜面反射 渐入渐出等效果。 这里只介绍阴影体和镜面的实现方式。 二.镜面反射:  镜面反射实现思路比较简单利用模板测试的方式分三次绘制即可实现: 1.

spark 大型项目实战(四十四):troubleshooting之控制shuffle reduce端缓冲大小以避免OOM

1. map端的task是不断的输出数据的,数据量可能是很大的。 但是,其实reduce端的task,并不是等到map端task将属于自己的那份数据全部写入磁盘文件之后,再去拉取的。map端写一点数据,reduce端task就会拉取一小部分数据,立即进行后面的聚合、算子函数的应用。 每次reduece能够拉取多少数据,就由buffer来决定。因为拉取过来的数据,都是先放在buffer中的。然