9

私は現在、物理シミュレーションを iPhone 自体のビデオに変換するプロジェクトに取り組んでいます。

これを行うために、現在 2 つの異なるループを使用しています。最初のループは、AVAssetWriterInput オブジェクトが EAGLView をポーリングしてさらに画像を取得するブロックで実行されます。EAGLView は、格納されている配列から画像を提供します。

もう 1 つのループは、実際のシミュレーションです。シミュレーションタイマーをオフにして、毎回事前に指定された時間差でティックを呼び出しています。tick が呼び出されるたびに、バッファーがスワップされた後、EAGLView のスワップ バッファー メソッドで新しい画像を作成します。この画像は、AVAssetWriter がポーリングする配列に配置されます。

配列が大きくなりすぎないようにするためのその他のコードもあります。

これはすべて正常に動作しますが、非常に遅いです。

私がやっていることは、概念的に、プロセス全体を本来よりも遅くしていることがありますか? また、glReadPixels よりも Open GL から画像を取得する高速な方法を知っている人はいますか?

4

4 に答える 4

3

ビデオ メモリは、書き込みが速く、読み取りが遅いように設計されています。そのため、テクスチャへのレンダリングを実行します。シーンをテクスチャにレンダリングするために作成したメソッド全体を次に示します (カスタム コンテナーがいくつかありますが、それらを独自のものに置き換えるのは非常に簡単だと思います)。

-(TextureInf*) makeSceneSnapshot {
    // create texture frame buffer
    GLuint textureFrameBuffer, sceneRenderTexture;

    glGenFramebuffersOES(1, &textureFrameBuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);

    // create texture to render scene to
    glGenTextures(1, &sceneRenderTexture);
    glBindTexture(GL_TEXTURE_2D, sceneRenderTexture);

    // create TextureInf object
    TextureInf* new_texture = new TextureInf();
    new_texture->setTextureID(sceneRenderTexture);
    new_texture->real_width = [self viewportWidth];
    new_texture->real_height = [self viewportHeight];

    //make sure the texture dimensions are power of 2
    new_texture->width = cast_to_power(new_texture->real_width, 2);
    new_texture->height = cast_to_power(new_texture->real_height, 2);

    //AABB2 = axis aligned bounding box (2D)
    AABB2 tex_box;

    tex_box.p1.x = 1 - (GLfloat)new_texture->real_width / (GLfloat)new_texture->width;
    tex_box.p1.y = 0;
    tex_box.p2.x = 1;
    tex_box.p2.y = (GLfloat)new_texture->real_height / (GLfloat)new_texture->height;
    new_texture->setTextureBox(tex_box);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  new_texture->width, new_texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, sceneRenderTexture, 0);

    // check for completness
    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
        new_texture->release();
        @throw [NSException exceptionWithName: EXCEPTION_NAME
                                       reason: [NSString stringWithFormat: @"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)]
                                     userInfo: nil];
        new_texture = nil;
    } else {
        // render to texture
        [self renderOneFrame];
    }

    glDeleteFramebuffersOES(1, &textureFrameBuffer);

    //restore default frame and render buffers
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, _defaultFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, _colorRenderbuffer);
    glEnable(GL_BLEND);         
    [self updateViewport];      
    glMatrixMode(GL_MODELVIEW);


    return new_texture;
}

もちろん、常にスナップショットを作成している場合は、テクスチャ フレームとレンダー バッファーを 1 回だけ作成する (そしてそれらにメモリを割り当てる) ことをお勧めします。

于 2011-02-05T09:08:01.260 に答える
1

CADisplayLinkオブジェクトを使用して、描画速度とキャプチャ速度がデバイスの画面のリフレッシュレートに対応していることを確認できます。デバイス画面の更新ごとに何度も更新およびキャプチャすることにより、実行ループの実行時間が遅くなっている可能性があります。

アプリの目標によっては、提示するすべてのフレームをキャプチャする必要がない場合があるため、セレクターで、現在のフレームをキャプチャするかどうかを選択できます。

于 2011-03-02T16:50:39.450 に答える
1

覚えておくべきことの 1 つは、GPU が CPU とは非同期で実行されていることです。そのため、レンダリングが終了した直後に glReadPixels を実行しようとすると、コマンドが GPU にフラッシュされてレンダリングされるまで待機してからコマンドを読み戻す必要があります。 .

同期的に待機する代わりに、スナップショットをテクスチャのキューにレンダリングします (Max が言及したような FBO を使用)。前のフレームの 1 つをデキューする前に、あと数フレームをレンダリングするまで待ってください。iPhone がフェンスや同期オブジェクトをサポートしているかどうかはわかりませんが、サポートしている場合は、それらをチェックして、ピクセルを読み取る前にレンダリングが終了したかどうかを確認できます。

于 2011-02-05T09:58:55.900 に答える
0

質問は新しいものではありませんが、まだ回答が得られていないので、参加したいと思いました.

glReadPixels は確かに非常に遅いため、パフォーマンスに悪影響を与えずに OpenGL アプリケーションからビデオを記録するために使用することはできません。

私たちは回避策を見つけ、パフォーマンスを損なうことなく、OpenGL ベースのグラフィックスをビデオ ファイルに記録できる Everyplay という無料の SDK を作成しました。https://developers.everyplay.com/で確認できます。

于 2013-02-06T08:10:53.677 に答える