FBO离屏渲染技术

时间:2021-10-06 05:07:56
接触Android开发不久就接触了离屏渲染的项目,现在搞了快一个月了,终于做出些模样。。。总结一下
1、首先应该清楚Activity的生命周期
加载activity——onCreate()——onStar()——onResume()——activity进入运行状态——(其它activity转入前台)——onPause()——activity进入暂停状态——该activity变为完全不可见——onStop()——activity进入停止状态——该activity被系统结束或者销毁——onDestroy——该activity进入销毁状态
当activity从暂停状态再次回到前台需调用onResume()函数
当activity从停止状态再次回到前台分两种情况:当用户再次启动该activity使之进入前台时,调用onRestart()——onStart()——onResume();当更高优先级的应用需要内存——activity应用进程被终止——用户再次启动该activity,调用onCreate()——onStart()——onResume()
生命周期弄明白了,就可以根据需求确定何时进行离屏渲染,本项目中确定activity进入暂停状态时开始实施离屏渲染,activity再次回到前台时停止离屏渲染


2、其次就要搞清楚FBO的机理
(1)FBO对象的创建与销毁
       void glGenFramebuffersEXT(GLsizei n, GLuint* ids);
       void glDeleteFramebuffersEXT(GLsizei n, const GLuint* ids);
       第一个参数是要创建的FBO的个数,第二个保存创建的FBO的ID。
(2)一旦FBO对象创建完毕,即要进行绑定
       void glBindFramebufferEXT(GLenum target, GLuint id);
       第一个参数必须是GL_FRAMEBUFFER_EXT
       第二个参数是第一步创建FBO对象中获取的id号,该id号是一个非0值,因为系统默认的FBO的id号是0,所以如果你想取消FBO的绑定,将id等于0作为id参数传递给该函数即可。
 (3)创建Renderbuffer Object
        void glGenRenderbuffersEXT(GLsizei n, GLuint* ids);
        void glDeleteRenderbuffersEXT(GLsizei n, const GLuint* ids);
(4)同样的,Renderbuffer Object创建好之后,要记得绑定。
        void glBindRenderbufferEXT(GLenum target, GLuint id)
(5)确定Renderbuffer Object的数据格式和尺寸。
      这一步很重要,因为我们只是创建了Renderbuffer Object,还没有为它提供一个存储数据的地方,也没有指定其存储数据的地方存储什么格式的数据,所以接下来就要做这个事情了。
      void glRenderbufferStorageEXT(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
      第一个参数必须是GL_RENDERBUFFER_EXT
      第二个参数可以是可渲染的颜色格式,如(GL_RGB, GL_RGBA, etc.),可渲染的深度格式(GL_DEPTH_COMPONENT)或者是可渲染的模板格式(GL_STENCIL_INDEX)。
      最后两个参数就是以像素为单位指定数据所要占用内存的大小。
      这里需要注意两点:
       1)指定的内存区域的宽和高应该都小于GL_MAX_RENDERBUFFER_SIZE_EXT,否则将产生GL_INVALID_VALUE错误。
       2)所有的texture object也好,renderbuffer object也好,其宽和高都是严格一致的。
 (6)指定挂接的对象
       glFramebufferTexture2DEXT函数挂接一个texture图像到FBO
       glFramebufferRenderbufferEXT函数挂接一个Renderbuffer图像到FBO
 (7)检测FBO状态
      该挂接的对象都挂接好了,在使用FBO之前,必须要检查FBO的状态是否处于完成状态。如果FBO处于未完成状态,那么绘制操作就会失败。如何获取FBO的完成状态呢?使用glCheckFramebufferStatusEXT函数。
 android系统下运用OpenGL  ES过程稍有简化,代码如下

    /**
     * FBO创建及绑定
     */   

private boolean createFbo(IntBuffer FBOTexure, IntBuffer depthBuffer, IntBuffer frameBuffer, float max) {

    /* 生成纹理 */
    GLES10.glGenTextures(1, FBOTexure);
    GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, FBOTexure.get(0));
    GLES10.glTexParameterf(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
    GLES10.glTexParameterf(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
    GLES10.glTexImage2D(GLES10.GL_TEXTURE_2D, 0, GLES10.GL_RGBA, (int) max, (int) max, 0, GLES10.GL_RGBA,
            GLES10.GL_UNSIGNED_BYTE, null);
    /* 生成深度缓存 */
    GLES11Ext.glGenRenderbuffersOES(1, depthBuffer);
    GLES11Ext.glBindRenderbufferOES(GLES11Ext.GL_RENDERBUFFER_OES, depthBuffer.get(0));
    GLES11Ext.glRenderbufferStorageOES(GLES11Ext.GL_RENDERBUFFER_OES, GLES11Ext.GL_DEPTH_COMPONENT16_OES,
            (int) max, (int) max);
    /* 生成fbo */
    GLES11Ext.glGenFramebuffersOES(1, frameBuffer);
    GLES11Ext.glBindFramebufferOES(GLES11Ext.GL_FRAMEBUFFER_OES, frameBuffer.get(0));
    /* 绑定 - 把图像连接到FBO*/
    GLES11Ext.glFramebufferTexture2DOES(GLES11Ext.GL_FRAMEBUFFER_OES, GLES11Ext.GL_COLOR_ATTACHMENT0_OES,
            GLES10.GL_TEXTURE_2D, FBOTexure.get(0), 0);
    GLES11Ext.glFramebufferRenderbufferOES(GLES11Ext.GL_FRAMEBUFFER_OES, GLES11Ext.GL_DEPTH_ATTACHMENT_OES,
            GLES11Ext.GL_RENDERBUFFER_OES, depthBuffer.get(0));
    /* 检查结果 */
    int uStatus = GLES11Ext.glCheckFramebufferStatusOES(GLES11Ext.GL_FRAMEBUFFER_OES);
    if (uStatus != GLES11Ext.GL_FRAMEBUFFER_COMPLETE_OES) {
        return false;
    }
    return true;
}

   /**
     * FBO绑定
     */  
    public void bindFbo() {
        if (!mIsFboCreated && mWidth > 0 && mHeight > 0) {
            float max = calPow(mWidth, mHeight) * 1.0f;
            if (mGLMapView != null) {
                initGLMapViewEGLContext(mGLSurfaceView); //用GLSurfaceView初始化EGL
                mIsFboCreated = createFbo(mFBOTexureA, mDepthBufferA, mFrameBufferA, max);//判断FBO是否创建成功
            }
        }
        if (mIsFboCreated) {//FBO创建成功
            if (isInBackGround) {
                if (!mEgl.eglMakeCurrent(mEglDisplay, mEglPBSurface, mEglPBSurface, mEglContext)) {
                }
            }
            GLES11Ext.glBindFramebufferOES(GLES11Ext.GL_FRAMEBUFFER_OES, mFrameBufferA.get(0));//绑定到帧缓冲区
            mGL.glPixelStorei(GL10.GL_UNPACK_ALIGNMENT, 1);//控制所读数据的对齐方式
            GLES10.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);//清除颜色缓冲以及深度缓冲
        }
    }