2012-05-04 40 views
5

Tôi cần phải viết trình kết xuất đồ họa 2 chiều OpenGL ES trên iOS. Nó sẽ vẽ một số nguyên thủy như đường thẳng và đa giác thành hình ảnh 2d (nó sẽ hiển thị bản đồ vectơ). Cách nào là tốt nhất để nhận hình ảnh từ ngữ cảnh OpenGL trong tác vụ đó? Ý tôi là, tôi có nên đưa những nguyên thủy này vào kết cấu và sau đó lấy hình ảnh từ nó hay không? Ngoài ra, nó sẽ là tuyệt vời nếu ai đó cung cấp cho các ví dụ hoặc hướng dẫn mà trông giống như những gì tôi cần (2d GL rendering vào hình ảnh). Cảm ơn trước!Hiển thị OpenGL ES 2d thành hình ảnh

Trả lời

19

Nếu bạn cần hiển thị cảnh OpenGL ES 2-D, sau đó trích xuất hình ảnh của cảnh đó để sử dụng bên ngoài OpenGL ES, bạn có hai tùy chọn chính.

Đầu tiên là chỉ đơn giản là làm cho khung cảnh của bạn và sử dụng glReadPixels() để lấy dữ liệu RGBA cho cảnh và đặt nó vào một mảng byte, như trong những điều sau đây:

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

Thứ hai, và nhanh hơn nhiều, cách làm điều này là hiển thị cảnh của bạn thành đối tượng framebuffer được hỗ trợ kết cấu (FBO), nơi kết cấu đã được cung cấp bởi bộ đệm kết cấu iOS 5.0. Tôi mô tả cách tiếp cận này trong this answer, mặc dù tôi không hiển thị mã để truy cập dữ liệu thô ở đó.

Bạn làm như sau để thiết lập bộ nhớ cache kết cấu và ràng buộc kết cấu 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); 

và sau đó bạn chỉ có thể đọc trực tiếp từ các byte mà sao kết cấu này (ở định dạng BGRA, không phải là RGBA của glReadPixels()) sử dụng một cái gì đó như:

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

Tuy nhiên, nếu bạn chỉ muốn sử dụng lại hình ảnh của bạn trong OpenGL ES, bạn chỉ cần để render cảnh của bạn đến một FBO texture hậu thuẫn và sau đó sử dụng kết cấu mà ở mức thứ hai của bạn dựng hình.

Tôi hiển thị ví dụ về hiển thị kết cấu và sau đó thực hiện một số xử lý trên mẫu, trong ứng dụng mẫu CubeExample trong khuôn khổ mã nguồn mở GPUImage của tôi, nếu bạn muốn thấy điều này hoạt động.

+0

cảm ơn rất nhiều, nhưng tính năng này chỉ hoạt động với iOS 5? – medvedNick

+0

@medvedNick - 'glReadPixels()' hoạt động trên tất cả các phiên bản hệ điều hành, nhưng bộ đệm kết cấu chỉ được giới thiệu lần đầu tiên trong iOS 5.0. Chúng nhanh hơn rất nhiều, nhưng chỉ có 5.0. Tuy nhiên, bạn có thể thực hiện kiểm tra thời gian chạy và quay lại 'glReadPixels()' chậm hơn trên các phiên bản hệ điều hành cũ hơn. Một lần nữa, kiểm tra mã GPUImage của tôi, bởi vì tôi làm điều này trong đó. –

+0

Bộ nhớ cache kết cấu là 5.0 trở lên, nhưng chúng không chỉ nhanh trên các thiết bị nhất định? ví dụ. Nhanh trên 4S/iPad2 và tương đương với glReadPixels/glTexImage2D ở mọi nơi khác –

Các vấn đề liên quan