1. 离屏渲染流程,基于opengles2.0
2.2.6下面选了SimpleGame例子,在jni中添加了nativeBegin和nativeEnd函数。最终离屏绘制流程:
nativeBegin(); nativeRender(); // cocos2dx的绘制。。。 nativeEnd();nativeBegin函数中,创建屏幕大小的fbo,绑定一个纹理和深度,然后绑定到当前创建的fbo上。nativeEnd中将fbo的纹理贴到屏幕上。。。
2. cocos2dx-2.2.6 下黑屏问题
但是运行以后结果是残忍的黑屏。。。好吧。又是状态错乱的问题,一步步排查吧:
nativeBegin和nativeEnd之间如果替换我自己render函数结果ok。进一步证明是nativeBegin和End函数与cocos2dx的render函数状态不吻合导致。追查了三天左右,最终问题定位在nativeEnd中renderQuad代码段上:
#if 0 // This section will call 0x500 Invalid Enum Error. glEnable(GL_TEXTURE_2D); checkGLError("glEnable"); #endif glActiveTexture(GL_TEXTURE0); checkGLError("glActiveTexture"); // glBindTexture(GL_TEXTURE_2D,mPostPass.color_id); glBindTexture(GL_TEXTURE_2D,mPass.color_id); checkGLError("glBindTexture"); glUniform1i(mBoard.uTexLoc,0); checkGLError("glUniform1i"); float vertices[] = {-1.0,1.0,-1.0,-1.0}; const float texcoords[] = {0,1,0}; glVertexAttribPointer(mBoard.aPosLoc,2,GL_FLOAT,GL_FALSE,vertices); glVertexAttribPointer(mBoard.aUVLoc,texcoords); glEnableVertexAttribArray(mBoard.aPosLoc); glEnableVertexAttribArray(mBoard.aUVLoc); glDrawArrays(GL_TRIANGLE_STRIP,4); #if 0 glDisableVertexAttribArray(mBoard.aUVLoc); glDisableVertexAttribArray(mBoard.aPosLoc); #endifopengles2.0中,不需要显式调用glEnable(TEXTURE_2D),否则LogCat中会报0x500错误。屏幕黑屏问题出在:绘制结束时候关闭了定点数组的纹理和位置属性。。。从而导致下一帧绘制时,cocos2dx中这两个属性也没有开启,从而绘制到fbo上的内容为黑。。。
3. cocos2dx-3.2下黑屏问题
2.2下面没问题了,放到3.2上面依然黑屏,而且logcat中没有警告和error。。这下郁闷了,据说2.x到3.x变化很大。为了差这个bug,把3.2的渲染代码也研究了下。。。引入vbo和批量绘制。回到黑屏问题上,没辙了只能通过glReadpixels试试读取帧内容写文件看。nativeRender函数刚开始一段时间,数据还没准备好是黑屏正常,直到数据准备好才有内容绘制。这点对我定位问题中干扰很大。因为刚开始渲染黑屏是正常的,大概100帧以后才开始有内容绘制。。。
为了测试构造一些特定场景:
当有内容绘制,begin和end中fbo才起作用:
0-100帧,nativeBegin和nativeEnd为空,nativeRender直接到屏幕。结果OK。
101帧,nativeBegin中fbo生效;1)nativeRender此时是否绘制正常?然后nativeEnd,2)此时屏幕上是否OK?
102帧,nativeBegin依然生效;上一帧的nativeBegin和nativeEnd已经生效,3)此时nativeRender否是绘制正常?4)nativeEnd完成屏幕如何?
103帧,重复102模式了。。。
问题4是比较明显,肯定是黑屏了。
问题1,2,3只能通过glReadPixels读取当前绑定的帧缓冲内容写文件看。。。结论是1处绘制正常,2处绘制正常,3处已经黑屏了。
是nativeEnd第一次执行后导致了后续nativeRender的失效。。。
最近花了两三天,最终定位到问题。3.2中对gl绘制状态进行了缓存,例如shaderProgram,textureId这些东西。。缓存的宏开关在ccConfig.h头文件中:
#ifndef CC_ENABLE_GL_STATE_CACHE #define CC_ENABLE_GL_STATE_CACHE 1 #endif
CC_ENABLE_GL_STATE_CACHE 定义成0,关闭GL状态缓存使用以后,结果ok。
或者不要直接调用gl的函数,而是通过ccGLStateCache组件中的接口调用GL指令,结果ok。