在iOS上渲染纹理OpenGL ES在模拟器上工作,但不在设备上

为了提高我的OpenGL ES应用程序在iPad上的性能,我打算绘制一个很less更新但重塑元素的纹理,所以我可以使用纹理,除非元素必须重绘。 然而,虽然纹理在模拟器和设备上都被正确地映射,但是只有在模拟器上才是真正渲染到纹理中的东西。

以下是我添加到项目中的代码。 在设置场景的同时,我创build了所需的缓冲区和纹理:

int width = 768; int height = 270; // Prepare texture for off-screen rendering. glGenTextures(1, &wTexture); glBindTexture(GL_TEXTURE_2D, wTexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); glClearColor(.9f, .3f, .6f, 1.0f); // DEBUG glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); // Depth attachment buffer, always needed. glGenRenderbuffersOES(1, &wDepth); glBindRenderbufferOES(GL_RENDERBUFFER_OES, wDepth); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height); glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0); // Create FBO for render-to-texture. glGenFramebuffersOES(1, &wBuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, wBuffer); glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, wTexture, 0); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, wDepth); glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 

新的FBO上的glFramebufferStatusOES (当然是未绑定的)在模拟器和设备上产生一个“framebuffer complete”返回值。 请注意,我为纹理设置了粉红色的清晰颜色,以确认纹理实际上是渲染的,问题实际上只是纹理从未被绘制。

每当纹理需要重绘时,我都会在渲染元素之前执行此操作:

 glBindFramebufferOES(GL_FRAMEBUFFER_OES, wBuffer); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); glMatrixMode(GL_MODELVIEW); glPushMatrix(); // ... 

以下的实际渲染后:

 // ... glPopMatrix(); glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 

最后,每当屏幕重新绘制时,我都会将纹理映射到屏幕上适当位置的四边形,如下所示:

 float Vertices[] = { -65.0f, -100.0f, .0f, -65.0f, 100.0f, .0f, -10.0f, -100.0f, .0f, -10.0f, 100.0f, .0f}; float Texture[] = {.0f, .0f, 1.0f, .0f, .0f, 1.0f, 1.0f, 1.0f}; glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glBindTexture(GL_TEXTURE_2D, wTexture); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glVertexPointer(3, GL_FLOAT, 0, Vertices); glTexCoordPointer(2, GL_FLOAT, 0, Texture); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); 

在iPhone和iPad模拟器(4.2,4.3)上,代码按预期工作。 我看到dynamic渲染的纹理显示在相应的位置,当然,由于我的debugging语句,用粉色代替透明背景。 然而,在我的iPad 4.2设备上,只渲染了粉红色的矩形,而不是渲染到纹理步骤中应该绘制的东西。 因此,纹理正确地呈现在屏幕上,但由于某种原因,在设备上,渲染到纹理的代码实际上没有向纹理渲染任何东西。

我想我正在使用一些设备上没有的function,或者在某个地方做出错误的假设,但我不知道它是什么。 我也尝试通过OpenGL ES分析器来运行它,但它只给我一些基本的性能优化提示。 我需要在哪里寻找问题?

我在我的项目中使用了MSAA,并发现当我禁用它时,问题消失了。 这导致我发现了另一个问题 ,其中讨论了相同的问题(但没有解决)。

问题似乎是,如果您的主帧缓冲器启用了多重采样,那么您所有的自定义FBO也必须使用多重采样。 您无法渲染到正常的非多重采样GL_TEXTURE_2D ,并且多重采样的GL_TEXTURE_2D_MULTISAMPLE在OpenGL ES 2上不可用。

为了解决这个问题,我修改了我的渲染到纹理代码,就像修改我的主渲染代码来启用多重采样一样。 除了在问题代码中创build的三个缓冲区对象之外,我还为多重采样的渲染创build了三个缓冲区对象:

 glGenFramebuffersOES(1, &wmBuffer); glGenRenderbuffersOES(1, &wmColor); glBindFramebufferOES(GL_FRAMEBUFFER_OES, wmBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, wmColor); glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_RGBA8_OES, width, height); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, wmColor); glGenRenderbuffersOES(1, &wmDepth); glBindRenderbufferOES(GL_RENDERBUFFER_OES, wmDepth); glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_DEPTH_COMPONENT16_OES, width, height); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, wmDepth); 

在渲染纹理之前,我绑定新的MSAA缓冲区:

 glBindFramebufferOES(GL_FRAMEBUFFER_OES, wmBuffer); 

最后,在渲染之后,我将MSAA FBOparsing为纹理FBO,就像我为我的主渲染帧缓冲区所做的那样:

 glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, wmBuffer); glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, wBuffer); glResolveMultisampleFramebufferAPPLE(); GLenum attachments[] = {GL_DEPTH_ATTACHMENT_OES, GL_COLOR_ATTACHMENT0_OES, GL_STENCIL_ATTACHMENT_OES}; glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 3, attachments); glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 

纹理现在渲染正确(性能非常好!)

Interesting Posts