2012-05-04 18 views
5

Potrzebuję napisać 2-wymiarowy renderer OpenGL ES na iOS. Powinien narysować pewne prymitywy, takie jak linie i wielokąty na obrazie 2D (będzie to renderowanie mapy wektorowej). Który sposób jest najlepszy do uzyskania obrazu z kontekstu OpenGL w tym zadaniu? Mam na myśli, czy powinienem uczynić te prymitywy teksturami, a potem uzyskać z nich obraz, czy co? Będzie też świetnie, jeśli ktoś da przykłady lub samouczki, które wyglądają jak to, czego potrzebuję (2d renderowania GL do obrazu). Z góry dziękuję!OpenGL ES 2d renderowanie do obrazu

Odpowiedz

19

Jeśli potrzebujesz renderować scenę OpenGL ES 2-D, a następnie wyodrębnić obraz tej sceny do użycia poza OpenGL ES, masz dwie główne opcje.

Pierwszym z nich jest po prostu renderować scenę i używać glReadPixels() aby pobrać dane RGBA na scenie i umieścić ją w tablicy bajtów, jak w poniższym przykładzie:

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

Druga, o wiele szybciej, sposób robienie tego ma na celu renderowanie twojej sceny do obiektu bufora ramki (FBO) z teksturami, na którym tekstura została dostarczona przez pamięci podręczne tekstur w systemie iOS 5.0. Opisuję to podejście w this answer, chociaż nie pokazuję tam kodu dostępu do surowych danych.

wykonać następujące czynności, aby skonfigurować pamięć podręczną tekstury i wiążą FBO Tekstura:

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

a następnie można tylko odczytać bezpośrednio z bajtów, które z powrotem w tym faktury (w formacie BGRA, a nie RGBA z glReadPixels()) używając coś takiego:

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

Jednakże, jeśli po prostu chcesz ponownie użyć obrazu w OpenGL ES, wystarczy, aby uczynić swoją scenę tekstury oparciem FBO a następnie wykorzystać tę fakturę w swoim drugim poziomie wykonanie.

Pokazuję przykład renderowania do tekstury, a następnie wykonuję na niej przetwarzanie, w przykładowej aplikacji CubeExample w ramach mojego open source GPUImage, jeśli chcesz zobaczyć to w akcji.

+0

wielkie dzięki, ale czy to działa tylko z iOS 5? – medvedNick

+0

@medvedNick - 'glReadPixels()' działa we wszystkich wersjach systemu operacyjnego, ale pamięci podręczne tekstur zostały wprowadzone dopiero w iOS 5.0. Są znacznie, dużo szybsze, ale mają tylko 5.0. Możesz jednak wykonać sprawdzanie w czasie wykonywania i powrócić do wolniejszego 'glReadPixels()' na starszych wersjach systemu operacyjnego. Ponownie sprawdź mój kod GPUImage, ponieważ robię to tutaj. –

+0

Skrytki tekstur mają wersję 5.0 i wyższą, ale czy nie są one szybkie tylko na niektórych urządzeniach? na przykład Szybko na 4S/iPad2 i odpowiednik glReadPixels/glTexImage2D wszędzie indziej. –