Android OpenGL-ES FBO(Frame Buffer Object)离屏渲染

##.FBO用途:
    OpenGL绘制需要一块“画布”,常见的方式是把GLSurfaceView中的Surface作为画布的载体,最终绘制好的画面会输出到GLSurfaceView对应的屏幕区域上。
    如果希望绘制的画面不显示出来,默默地在后台作画,那就需要换一张“画布”,不要把画面最终输出到屏幕上。
    一般是通过FBO方式来实现这一功能。(当然,如果仅仅是希望不显示到屏幕上,那么只要“画布”上的画面最终不被SurfaceFlinger消耗就行了,也并非一定要用FBO)
##.FBO简介:
    FBO(Frame Buffer Object),即帧缓冲对象,是帧缓冲区的封装对象,它本身是一个容器,自身不能用于渲染,需要与一些可渲染的缓冲区绑定在一起,如纹理或者其它类型的渲染缓冲区。FBO不受窗口大小限制,可以包含多个颜色缓冲区,可以同时从一个片元着色器写入。
    如只是对一个图像做变色处理等,只绑定纹理即可。如果需要往一个图像上增加3D的模型和贴纸,则一定还要绑定depth Render Buffer。
##.使用的代码示例和注解
1.创建帧缓冲并绑定到输出纹理
//1.创建纹理ID,对应于FBO输出的画面纹理
int[] outputTextureId = new int[1];
GLES20.glGenTextures(1, outputTextureId, 0);
mCameraTextureOutputId = outputTextureId[0];

//2.创建帧缓冲区对象的ID(Frame Buffer Object,即FBO)
//这里只需要用到2D纹理,不会用到3D的模型和贴纸,所以不需要额外创建和绑定depth Render Buffer
int[] frameBufferId = new int[1];
GLES20.glGenFramebuffers(1, frameBufferId, 0);
mCameraFrameBufferId = frameBufferId[0];

//3.创建纹理对应的存储空间、帧缓冲区对象并绑定对应输出纹理
//绑定纹理并设置对应参数。(注:绑定纹理后到目标类型后,后继针对该目标类型的操作都是针对当前绑定的纹理。)
GLESUtils.bindTexture(GLES20.GL_TEXTURE_2D, mCameraTextureOutputId);
//指明纹理大小,创建对应的存储空间
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
        outputFboTextureWidth, outputFboTextureHeight, 0,
        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
//创建FrameBuffer Object并绑定对应Id
//(注:绑定帧缓冲区后,绘制时会绘制到帧缓冲区绑定的纹理上,而不会绘制到View上)
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mCameraFrameBufferId);
//为FrameBuffer Object绑定对应的输出纹理
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
        mCameraTextureOutputId, 0);
//解绑定纹理,避免后继操作别的纹理时误操作了上一个绑定的纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
//解绑定帧缓冲区,后继绘制流程中再决定绑定到哪个帧缓冲区 或者直接绘制到View上
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
2.绘制时的使用
//重新绑定帧缓冲区
//绑定帧缓冲区后,绘制时会绘制到帧缓冲区绑定的纹理上,而不会绘制到View上
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);
// 设置OpenGL视口的位置与大小, 最终图像会被输出到屏幕或目标纹理的视口对应的区域显示
//    例如图像最终被渲染到GlSurfaceView上,则在此处定义的是显示在GlSurfaceView的Surface上的哪个区域
// 注意该API所采用的坐标系,与OpenGl中的默认纹理坐标系方向相同,
//    即以Surface的左下角为原点(0,0),向右为x轴正方向,向上为y轴正方向.
// OpenGl世界坐标系上经过层层矩阵变换,最后被裁剪空间选中的部分会投射出一副二维画面显示在这个区域上,
//    这张输出画面会拉伸显示到这个区域上,但若设置的视口区域超出实际Surface,超出的部分不会显示。
GLES20.glViewport(0,0, outputWidth, outputHeight);
//设置背景颜色
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//清除深度缓冲区
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
//...............后继绘制逻辑..................

猜你喜欢

转载自blog.csdn.net/u013914309/article/details/124692031