9

我目前正在做一个项目,将物理模拟转换为 iPhone 上的视频。

为此,我目前正在使用两个不同的循环。第一个循环在 AVAssetWriterInput 对象轮询 EAGLView 以获取更多图像的块中运行。EAGLView 提供来自存储它们的数组中的图像。

另一个循环是实际模拟。我已经关闭了模拟计时器,并且每次都以预先指定的时间差自己调用滴答声。每次调用滴答声时,我都会在交换缓冲区后在 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;
}

当然,如果你一直在做快照,那么你最好只创建一次纹理帧和渲染缓冲区(并为它们分配内存)。

于 2011-02-05T09:08:01.260 回答
1

您可以尝试使用 CADisplayLink 对象来确保您的绘图率和捕获率与设备的屏幕刷新率相对应。每次设备屏幕刷新时刷新和捕获太多次,您可能会减慢运行循环的执行时间。

根据您的应用程序的目标,您可能没有必要捕获您呈现的每一帧,因此在您的选择器中,您可以选择是否捕获当前帧。

于 2011-03-02T16:50:39.450 回答
1

要记住的一件事是 GPU 与 CPU 异步运行,因此如果您在完成渲染后立即尝试执行 glReadPixels,则必须等待命令刷新到 GPU 并渲染,然后才能读回它们.

与其同步等待,不如将快照渲染到纹理队列中(使用 Max 提到的 FBO)。等到您渲染了更多帧,然后再将前一个帧中的一个出队。我不知道 iPhone 是否支持栅栏或同步对象,但如果支持,您可以在读取像素之前检查它们以查看渲染是否已完成。

于 2011-02-05T09:58:55.900 回答
0

虽然这个问题不是新问题,但还没有回答,所以我想我会参与其中。

glReadPixels 确实非常慢,因此不能用于从 OpenGL 应用程序录制视频而不会对性能产生不利影响。

我们确实找到了一种解决方法,并创建了一个名为 Everyplay 的免费 SDK,它可以将基于 OpenGL 的图形录制到视频文件中,而不会降低性能。您可以在https://developers.everyplay.com/上查看

于 2013-02-06T08:10:53.677 回答