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の AglFramebufferStatusOESは (もちろんアンバインドされる前に)、シミュレーターとデバイスの両方で「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 アナライザーで実行してみましたが、基本的なパフォーマンス最適化のヒントしか得られません。どこで問題を探す必要がありますか?

4

1 に答える 1

9

プロジェクトで MSAA を使用していましたが、無効にすると問題が解決したことがわかりました。これにより、同じ問題が議論されている(ただし解決されていない)別の質問を発見するようになりました。

問題は、メイン フレーム バッファでマルチサンプリングが有効になっている場合、すべてのカスタム FBO もマルチサンプリングを使用する必要があることです。通常の非マルチサンプルGL_TEXTURE_2Dにレンダリングすることはできず、マルチサンプルGL_TEXTURE_2D_MULTISAMPLEは OpenGL ES 2 では使用できません。

この問題を修正するために、マルチサンプリングを有効にするためにメイン レンダリング コードを変更したのと同じ方法で、レンダリングからテクスチャへのコードを変更しました。質問のコードで作成された 3 つのバッファー オブジェクトに加えて、マルチサンプリング レンダリング用にさらに 3 つ作成します。

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

テクスチャが正しくレンダリングされるようになりました (そしてパフォーマンスは素晴らしいです!)

于 2011-09-12T09:06:47.113 に答える