渲染到iOS上的纹理OpenGL ES可以在模拟器上运行,但不能在设备上运行 [英] Rendering to texture on iOS OpenGL ES—works on simulator, but not on device

查看:135
本文介绍了渲染到iOS上的纹理OpenGL ES可以在模拟器上运行,但不能在设备上运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了提高我的iPad OpenGL ES应用程序的性能,我计划在纹理上绘制一个很少更新但是渲染时重的元素,所以除非必须重新绘制元素,否则我可以使用纹理。但是,虽然纹理在模拟器和设备上都正确映射,但只有在模拟器上实际渲染到纹理中。

In order to improve the performance of my OpenGL ES application for the iPad, I was planning to draw a rarely updated but rendertime-heavy element to a texture, so I can just use the texture unless the element has to be redrawn. However, while the texture is mapped correctly on both the simulator and the device, only on the simulator is something actually rendered into the texture.

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

The following is the code that I added to the project. While setting up the scene, I create the buffers and the texture needed:

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'返回值。请注意,我为纹理设置了粉红色的清晰颜色,以确认纹理实际呈现,问题实际上只是纹理从未被绘制。

A glFramebufferStatusOES on the new FBO (before it is unbound of course) yields a 'framebuffer complete' return value on both the simulator and the device. Note that I set the pink clear colour for the texture in order to confirm that the texture is actually rendered, and the problem is in fact simply that the texture is never drawn into.

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

Whenever the texture needs to be redrawn, I do this before rendering the element:

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

以及实际渲染后的以下内容:

and the following after the actual rendering:

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

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

Finally, every time the screen is redrawn I map the texture to a quad at the appropriate position on the screen, like so:

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设备上,只渲染粉红色矩形,而不是在渲染到纹理步骤中应该绘制的粉红色矩形。因此,纹理正确地呈现在屏幕上,但由于某种原因,在设备上渲染到纹理代码无法实际渲染任何纹理。

On the iPhone and iPad simulators (4.2, 4.3), the code works as expected. I see the dynamically rendered texture displayed at the respective position, of course with a pink instead of a transparent background due to my debugging statement. On my iPad 4.2 device, however, only the pink rectangle is rendered, not what should have been drawn into it during the render-to-texture step. Thus, the texture is rendered to the screen correctly, but for some reason, on the device the render-to-texture code fails to actually render anything to the texture.

我想我正在使用设备上没有的某些功能,或者在某处做出错误的假设,但我无法弄清楚它是什么。我也试过通过OpenGL ES Analyzer运行它,但它只给我一些基本的性能优化提示。我在哪里需要查找问题?

I suppose I am using some functionality that is not available on the device, or make an erroneus assumption somewhere, but I can't figure out what it is. I also tried running it through the OpenGL ES Analyzer, but it gives me nothing but some basic performance optimisation tips. Where do I need to look for the problem?

推荐答案

我在我的项目中使用MSAA,并发现问题所在我禁用它时消失了。这让我发现了这个问题讨论相同问题(但未解决)。

I was using MSAA in my project, and have found out that the problem disappeared when I disabled it. This has lead me to discover this other question where the same problem is discussed (but not solved).

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

The problem seems to be that if multisampling is enabled for your main framebuffer, all of your custom FBOs have to use multisampling as well. You cannot render to a normal non-multisampled GL_TEXTURE_2D, and a multi-sampled GL_TEXTURE_2D_MULTISAMPLE is not available on OpenGL ES 2.

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

In order to fix the problem, I modified my render-to-texture code the same way I modified my main rendering code to enable multisampling. In addition to the three buffer objects created in the code from the question, I create three more for the multi-sampled rendering:

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缓冲区:

Before rendering to the texture, I bind the new MSAA buffer:

glBindFramebufferOES(GL_FRAMEBUFFER_OES, wmBuffer);

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

Finally, after rendering, I resolve the MSAA FBO into the texture FBO the same way I do for my main rendering framebuffer:

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);

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

The textures are now rendered correctly (and the performance is great!)

这篇关于渲染到iOS上的纹理OpenGL ES可以在模拟器上运行,但不能在设备上运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆