OpenGL ES 2d рендеринг в изображение

Мне нужно написать OpenGL ES 2-мерный рендерер на iOS. Он должен нарисовать некоторые примитивы, такие как линии и многоугольники, в 2D-изображение (это будет рендеринг векторной карты). Каким способом лучше всего получить изображение из контекста OpenGL в этой задаче? Я имею в виду, я должен визуализировать эти примитивы в текстуру, а затем получить изображение из нее, или как? Также было бы хорошо, если бы кто-то давал примеры или учебные пособия, которые выглядят так, как мне нужно (2d GL рендеринг в изображение). Заранее спасибо!

1 ответ

Решение

Если вам нужно визуализировать сцену OpenGL ES 2-D, а затем извлечь изображение этой сцены для использования вне OpenGL ES, у вас есть два основных варианта.

Во-первых, просто визуализировать вашу сцену и использовать glReadPixels() чтобы получить данные RGBA для сцены и поместить их в байтовый массив, как показано ниже:

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

Второй, и гораздо более быстрый, способ сделать это состоит в том, чтобы визуализировать вашу сцену в объектно-поддерживаемый объект кадрового буфера (FBO), где текстура была предоставлена ​​кешами текстур iOS 5.0. Я описываю этот подход в этом ответе, хотя я не показываю код для доступа к необработанным данным.

Вы делаете следующее, чтобы настроить кеш текстуры и привязать текстуру 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);

а затем вы можете просто читать непосредственно из байтов, которые поддерживают эту текстуру (в формате BGRA, а не RGBA glReadPixels()) используя что-то вроде:

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

Однако, если вы просто хотите повторно использовать изображение в OpenGL ES, вам просто нужно визуализировать вашу сцену в FBO на текстурной основе, а затем использовать эту текстуру на втором уровне рендеринга.

Я показываю пример рендеринга в текстуру, а затем выполняю некоторую обработку на ней, в образце приложения CubeExample в моей среде с открытым исходным кодом GPUImage, если вы хотите увидеть это в действии.

Другие вопросы по тегам