2012-05-04 11 views
5

Ho bisogno di scrivere il renderer 2D bidimensionale di OpenGL su iOS. Dovrebbe disegnare alcune primitive come linee e poligoni in un'immagine 2D (sarà il rendering della mappa vettoriale). Qual è il modo migliore per ottenere immagini dal contesto OpenGL in quell'attività? Voglio dire, dovrei renderizzare queste primitive in texture e poi ottenere un'immagine da esso, o cosa? Inoltre, sarà fantastico se qualcuno fornirà esempi o tutorial che assomiglino alla cosa di cui ho bisogno (rendering 2D in immagine). Grazie in anticipo!OpenGL ES 2d rendering nell'immagine

risposta

19

Se è necessario eseguire il rendering di una scena 2D 2D di OpenGL, quindi estrarre un'immagine di quella scena da utilizzare all'esterno di OpenGL ES, sono disponibili due opzioni principali.

Il primo è quello di rendere semplice la scena e utilizzare glReadPixels() per afferrare i dati RGBA per la scena e metterlo in un array di byte, come nel seguente:

GLubyte *rawImagePixels = (GLubyte *)malloc(totalBytesForImage); 
glReadPixels(0, 0, (int)currentFBOSize.width, (int)currentFBOSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels); 
// Do something with the image 
free(rawImagePixels); 

Il secondo, e molto più veloce, strada in questo modo si esegue il rendering della scena su un oggetto framebuffer (FBO) texture-backed, in cui la texture è stata fornita dalle cache di texture di iOS 5.0. Descrivo questo approccio in this answer, sebbene non mostri il codice per l'accesso ai dati grezzi.

effettuare le seguenti operazioni per impostare la cache di consistenza e legare la trama FBO:

CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, (__bridge void *)[[GPUImageOpenGLESContext sharedImageProcessingOpenGLESContext] context], NULL, &rawDataTextureCache); 
    if (err) 
    { 
     NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreate %d"); 
    } 

    // Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/ 

    CFDictionaryRef empty; // empty value for attr value. 
    CFMutableDictionaryRef attrs; 
    empty = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary 
           NULL, 
           NULL, 
           0, 
           &kCFTypeDictionaryKeyCallBacks, 
           &kCFTypeDictionaryValueCallBacks); 
    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 
             1, 
             &kCFTypeDictionaryKeyCallBacks, 
             &kCFTypeDictionaryValueCallBacks); 

    CFDictionarySetValue(attrs, 
         kCVPixelBufferIOSurfacePropertiesKey, 
         empty); 

    //CVPixelBufferPoolCreatePixelBuffer (NULL, [assetWriterPixelBufferInput pixelBufferPool], &renderTarget); 

    CVPixelBufferCreate(kCFAllocatorDefault, 
         (int)imageSize.width, 
         (int)imageSize.height, 
         kCVPixelFormatType_32BGRA, 
         attrs, 
         &renderTarget); 

    CVOpenGLESTextureRef renderTexture; 
    CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, 
                rawDataTextureCache, renderTarget, 
                NULL, // texture attributes 
                GL_TEXTURE_2D, 
                GL_RGBA, // opengl format 
                (int)imageSize.width, 
                (int)imageSize.height, 
                GL_BGRA, // native iOS format 
                GL_UNSIGNED_BYTE, 
                0, 
                &renderTexture); 
    CFRelease(attrs); 
    CFRelease(empty); 
    glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture)); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0); 

e poi si può solo leggere direttamente dai byte che appoggiano questa texture (in formato BGRA, non il RGBA di glReadPixels()) utilizzando qualcosa di simile:

CVPixelBufferLockBaseAddress(renderTarget, 0); 
    _rawBytesForImage = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget); 
    // Do something with the bytes 
    CVPixelBufferUnlockBaseAddress(renderTarget, 0); 

Tuttavia, se si desidera solo per riutilizzare la vostra immagine all'interno di OpenGL ES, è sufficiente a rendere la scena ad un FBO tessitura sostenuta e quindi utilizzare tale consistenza nel secondo livello di il rendering.

Mostrare un esempio di rendering a una trama e quindi eseguire alcune elaborazioni su di esso, all'interno dell'applicazione di esempio CubeExample all'interno del mio framework open source GPUImage, se si desidera vederlo in azione.

+0

grazie mille, ma funziona solo con iOS 5? – medvedNick

+0

@medvedNick - 'glReadPixels()' funziona su tutte le versioni del sistema operativo, ma le cache delle texture sono state introdotte solo per la prima volta in iOS 5.0. Sono molto, molto più veloci, ma sono solo 5.0. È possibile eseguire un controllo di runtime, tuttavia, e tornare al più lento 'glReadPixels()' nelle versioni precedenti del sistema operativo. Di nuovo, controlla il mio codice GPUImage, perché lo faccio lì. –

+0

Le cache texture sono 5.0 e successive, ma non sono veloci solo su determinati dispositivi? per esempio. Veloce su 4S/iPad2 e equivalente a glReadPixels/glTexImage2D ovunque altrove –