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);//清除颜色缓冲以及深度缓冲
}
}