在iOS OpenGL ES上进行纹理渲染-在模拟器上正常工作,但在设备上不起作用。

9
为了提高iPad上我的OpenGL ES应用程序的性能,我计划将一个稀疏更新但渲染时间长的元素绘制到纹理中,这样除非必须重新绘制该元素,否则我可以直接使用该纹理。然而,虽然在模拟器和设备上都正确地映射了纹理,但只有在模拟器上才会实际渲染到纹理中。
以下是我添加到项目中的代码。在设置场景时,我创建所需的缓冲区和纹理:
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)上,代码的运行结果符合预期。我看到了动态渲染纹理在相应位置正确地显示,当然由于我的调试语句,背景颜色是粉色而不是透明的。然而,在我的iPad 4.2设备上,只有粉色矩形被渲染,没有在渲染到纹理步骤中应该被绘制到其中的内容。因此,纹理被正确地渲染到屏幕上,但由于某些原因,在设备上,渲染到纹理的代码未能实际渲染任何东西到纹理中。
我想我可能使用了一些设备上不可用的功能,或者在某个地方做出了错误的假设,但我无法找出问题所在。我还尝试通过OpenGL ES分析器运行它,但除了一些基本的性能优化提示之外,什么也没给我。我需要在哪里寻找这个问题?
1个回答

9
我在项目中使用了MSAA,但发现禁用它后问题消失了。这使我发现了这个问题,其中讨论了同样的问题(但未解决)。
问题似乎是,如果为主帧缓冲启用了多重采样,则所有自定义FBO也必须使用多重采样。您无法渲染到普通的非多重采样GL_TEXTURE_2D,而OpenGL ES 2上没有可用的多重采样GL_TEXTURE_2D_MULTISAMPLE
为了解决这个问题,我修改了我的渲染到纹理代码,与我修改主渲染代码以启用多重采样的方式相同。除了从问题代码中创建的三个缓冲对象外,我为多重采样渲染创建了另外三个缓冲对象:
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 FBO到纹理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);

纹理现在呈现正确(性能也很棒!)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接