在iOS上渲染紋理OpenGL ES在模擬器上工作,但不在設備上



rendering opengl (1)

我在我的項目中使用了MSAA,並發現當我禁用它時,問題消失了。 這導致我發現了另一個問題 ,其中討論了相同的問題(但沒有解決)。

問題似乎是,如果您的主幀緩衝器啟用了多重採樣,那麼您所有的自定義FBO也必須使用多重採樣。 您無法渲染到正常的非多重採樣GL_TEXTURE_2D ,並且多重採樣的GL_TEXTURE_2D_MULTISAMPLE在OpenGL ES 2上不可用。

為了解決這個問題,我修改了我的渲染到紋理代碼,就像修改我的主渲染代碼來啟用多重採樣一樣。 除了在問題代碼中創建的三個緩衝區對象之外,我還為多重採樣的渲染創建了三個緩衝區對象:

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

紋理現在渲染正確(性能非常好!)

為了提高我的OpenGL ES應用程序在iPad上的性能,我打算繪製一個很少更新但重塑元素的紋理,所以我可以使用紋理,除非元素必須重繪。 然而,雖然紋理在模擬器和設備上都被正確地映射,但是只有在模擬器上才是真正渲染到紋理中的東西。

以下是我添加到項目中的代碼。 在設置場景的同時,我創建了所需的緩衝區和紋理:

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分析器來運行它,但它只給我一些基本的性能優化提示。 我需要在哪裡尋找問題?