2011-01-27 13 views
10

Actualmente estoy trabajando en un proyecto para convertir una simulación de física a un video en el iPhone.OpenGL para video en el iPhone

Para hacer esto, actualmente estoy usando dos bucles diferentes. El primer bucle se ejecuta en el bloque donde el objeto AVAssetWriterInput sondea el EAGLView para obtener más imágenes. EAGLView proporciona las imágenes de una matriz donde se almacenan.

El otro lazo es la simulación real. Apagué el temporizador de simulación y llamo a la marca yo mismo con una diferencia de tiempo preestablecida cada vez. Cada vez que se llama a un tic, creo una nueva imagen en el método de buffer de intercambio de EAGLView después de que los buffers han sido intercambiados. Esta imagen luego se coloca en la matriz que AVAssetWriter sondea.

También hay algo de código misceláneo para asegurarse de que la matriz no sea demasiado grande

Todo esto funciona bien, pero es muy, muy lento.

¿Hay algo que estoy haciendo que, conceptualmente, hace que todo el proceso sea más lento de lo que podría ser? Además, ¿alguien sabe de una forma más rápida de obtener una imagen de Open GL que glReadPixels?

+0

En primer lugar, ¿ha utilizado Instruments (Time Profiler, Shark) para comprobarse a sí mismo qué funciones están ocupando la mayor cantidad de tiempo? – makdad

Respuesta

3

La memoria de video está diseñada para que sea rápida de escribir y lenta para leer. Es por eso que realizo renderizado a textura. Aquí está todo el método que he creado para la representación de la escena de la textura (hay algunos envases personalizados, pero creo que es bastante sencillo para sustituirlos por su cuenta):

-(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; 
} 

Por supuesto, si usted' Al hacer snapshots todo el tiempo, será mejor que cree un frame de textura y represente búferes solo una vez (y asigne memoria para ellos).

1

Una cosa para recordar es que la GPU se ejecuta de forma asíncrona desde la CPU, por lo que si intenta hacer glReadPixels inmediatamente después de terminar de renderizar, tendrá que esperar a que los comandos se descarguen a la GPU y se procesen antes puede leerlos de vuelta.

En lugar de esperar sincrónicamente, renderice instantáneas en una cola de texturas (usando FBO como Max mencionado). Espera hasta que hayas renderizado un par de cuadros más antes de eliminar uno de los cuadros anteriores. No sé si el iPhone admite vallas o sincroniza objetos, pero si es así, puede verificarlos para ver si el renderizado finalizó antes de leer los píxeles.

1

Puede intentar usar un objeto CADisplayLink para asegurarse de que su velocidad de dibujo y su velocidad de captura correspondan a la frecuencia de actualización de la pantalla del dispositivo. Es posible que esté ralentizando el tiempo de ejecución del ciclo de ejecución al actualizar y capturar demasiadas veces por actualización de pantalla del dispositivo.

Dependiendo de los objetivos de su aplicación, puede que no sea necesario que capture cada fotograma que presente, por lo que en el selector, puede elegir si desea capturar el fotograma actual.

0

Si bien la cuestión no es nueva, no es contestado todavía, así que pensé que iba a lanzar en.

glReadPixels es de hecho muy lento, y por lo tanto no se puede utilizar para grabar vídeo desde una OpenGL aplicación sin adversamente afectando el rendimiento

Encontramos una solución y hemos creado un SDK gratuito llamado Everyplay que puede grabar gráficos basados ​​en OpenGL en un archivo de video, sin pérdida de rendimiento.Puede verificarlo en https://developers.everyplay.com/