FBO的一点理解

在使用glsurfaceView渲染图片和摄像头采集的视频数据时候,之前默认的使用直接渲染的方式。但是在实际的开发使用中,我们很多时候并不想要直接渲染,而是先做一些额外的工作,比如滤镜 。 fbo可以帮我们更好的实现这个需求,FBO可以让不渲染到屏幕当中去,而是渲染到离屏的buffer中。

这里我们不再去赘述一些基本的概念 ,基于OpenGL es 30 版本,在Android上的实现,描述一次 fbo的实现过程。

就以渲染一张bitmap为例 。

1. 创建bitmap纹理

  1. 生成并绑定纹理
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的创建

  1. 创建frameBuffer
    1
    2
    3
    //创建FrameBuffer
    mFrameBuffers = new int[1];
    GLES30.glGenFramebuffers(mFrameBuffers.length, mFrameBuffers, 0);
  2. 创建并绑定纹理
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. 设置纹理格式
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);
  1. 绑定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. 取消绑定
1
2
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
  1. 绘制
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 地址