在使用glsurfaceView渲染图片和摄像头采集的视频数据时候,之前默认的使用直接渲染的方式。但是在实际的开发使用中,我们很多时候并不想要直接渲染,而是先做一些额外的工作,比如滤镜 。 fbo可以帮我们更好的实现这个需求,FBO可以让不渲染到屏幕当中去,而是渲染到离屏的buffer中。
这里我们不再去赘述一些基本的概念 ,基于OpenGL es 30 版本,在Android上的实现,描述一次 fbo的实现过程。
就以渲染一张bitmap为例 。
1. 创建bitmap纹理
- 生成并绑定纹理
1 2 3 4 5 6 7 8 9 10
| final int[] textureIds = new int[1]; GLES30.glGenTextures(1, textureIds, 0); // 绑定纹理到OpenGL GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,textureIds[0]); //设置默认的纹理过滤参数 GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER,GLES30.GL_LINEAR_MIPMAP_LINEAR); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER,GLES30.GL_LINEAR);
|
2: 渲染bitmap到纹理
在上一步绑定纹理以后,后续的操作都会在此纹理完成
1 2 3 4
| // 加载bitmap到纹理中 GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D);
|
3 : 一定要记得解绑
1 2 3 4
| // 数据如果已经被加载进OpenGL,则可以回收该bitmap bitmap.recycle(); // 取消绑定纹理 GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
|
2. fbo的创建
- 创建frameBuffer
1 2 3
| //创建FrameBuffer mFrameBuffers = new int[1]; GLES30.glGenFramebuffers(mFrameBuffers.length, mFrameBuffers, 0);
|
- 创建并绑定纹理
1 2 3 4 5 6 7 8 9 10
| mFBOTextures = new int[1]; GLES30.glGenTextures(mFBOTextures.length, mFBOTextures, 0); GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mFBOTextures[0]); //设置参数 GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
|
- 设置纹理格式
1 2 3
| //指定FBO纹理的输出图像的格式 RGBA GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mWidth, mHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
|
- 绑定framebuffer
1 2 3 4 5
| GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFrameBuffers[0]);
//将fbo绑定到2d的纹理上 GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mFBOTextures[0], 0);
|
- 取消绑定
1 2
| GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0); GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
|
- 绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public int draw(int textureId) {
//锁定绘制的区域 绘制是从左下角开始的 GLES30.glViewport(0, 0, mWidth, mHeight); //绑定FBO,在FBO上操作 GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFrameBuffers[0]) //使用着色器 GLES30.glUseProgram(mProgram); ....... //激活纹理 GLES30.glActiveTexture(GLES30.GL_TEXTURE0); //绑定纹理 GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0); return mFBOTextures[0]; }
|
DEMO 地址