2012-09-24 25 views
5

Tôi gặp sự cố với chế độ xem OpenGL. Tôi có hai chế độ xem OpenGL. Chế độ xem thứ hai được thêm dưới dạng chế độ xem phụ vào chế độ xem chính. Hai khung nhìn opengl được vẽ trong hai ngữ cảnh khác nhau. Tôi cần chụp màn hình với hai chế độ xem opengl.Sự cố với "renderincontext" với chế độ xem opengl

Vấn đề là nếu tôi cố gắng để làm cho một CAEAGLLayer trong một bối cảnh như sau:

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextTranslateCTM(context, 1*(self.frame.size.width*0.5), 1*(self.frame.size.height*0.5)); 
CGContextScaleCTM(context, 3, 3); 
CGContextTranslateCTM(context, abcd, abcd); 

CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.myOwnView.layer; 
[eaglLayer renderInContext:context]; 

nó không hoạt động. Nếu tôi thấy bối cảnh (cho đầu ra dưới dạng hình ảnh), Nội dung trong lớp opengl bị thiếu. Nhưng tôi thấy thanh công cụ và hình ảnh 2d được gắn vào khung nhìn, trong hình ảnh đầu ra. Tôi không chắc chắn về vấn đề này. Hãy giúp tôi.

Trả lời

5

Tôi gặp sự cố tương tự và tìm thấy giải pháp thanh lịch hơn nhiều. Về cơ bản, bạn phân lớp CAEAGLLayer và thêm triển khai renderInContext của riêng bạn mà chỉ yêu cầu khung nhìn OpenGL để hiển thị nội dung bằng cách sử dụng glReadPixels. Cái đẹp là bây giờ bạn có thể gọi renderInContext trên bất kỳ lớp nào trong cấu trúc phân cấp, và kết quả là một ảnh chụp màn hình hoàn chỉnh, hoàn hảo, bao gồm cả khung nhìn OpenGL của bạn!

renderInContext của chúng tôi trong CAEAGLLayer subclassed là:

- (void)renderInContext:(CGContextRef)ctx 
{ 
    [super renderInContext: ctx]; 
    [self.delegate renderInContext: ctx]; 
} 

Sau đó, trong giao diện OpenGL chúng ta thay thế layerClass để nó trả về lớp con của chúng tôi thay vì vani CAEAGLLayer đồng bằng:

+ (Class)layerClass 
{ 
    return [MyCAEAGLLayer class]; 
} 

Chúng tôi thêm một phương thức trong chế độ xem để thực sự hiển thị nội dung của chế độ xem vào ngữ cảnh. Lưu ý rằng mã này PHẢI chạy sau khi chế độ xem GL của bạn đã được hiển thị, nhưng trước khi bạn gọi presentRenderbuffer để bộ đệm hiển thị sẽ chứa khung của bạn. Nếu không, hình ảnh kết quả sẽ rất có thể bị trống (bạn có thể thấy hành vi khác nhau giữa thiết bị và trình mô phỏng trên vấn đề cụ thể này).

- (void) renderInContext: (CGContextRef) context 
{ 
    GLint backingWidth, backingHeight; 

    // Bind the color renderbuffer used to render the OpenGL ES view 
    // If your application only creates a single color renderbuffer which is already bound at this point, 
    // this call is redundant, but it is needed if you're dealing with multiple renderbuffers. 
    // Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class. 
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer); 

    // Get the size of the backing CAEAGLLayer 
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); 
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); 

    NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight; 
    NSInteger dataLength = width * height * 4; 
    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte)); 

    // Read pixel data from the framebuffer 
    glPixelStorei(GL_PACK_ALIGNMENT, 4); 
    glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); 

    // Create a CGImage with the pixel data 
    // If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel 
    // otherwise, use kCGImageAlphaPremultipliedLast 
    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL); 
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 
    CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, 
            ref, NULL, true, kCGRenderingIntentDefault); 

    CGFloat scale = self.contentScaleFactor; 
    NSInteger widthInPoints, heightInPoints; 
    widthInPoints = width/scale; 
    heightInPoints = height/scale; 

    // UIKit coordinate system is upside down to GL/Quartz coordinate system 
    // Flip the CGImage by rendering it to the flipped bitmap context 
    // The size of the destination area is measured in POINTS 
    CGContextSetBlendMode(context, kCGBlendModeCopy); 
    CGContextDrawImage(context, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref); 

    // Clean up 
    free(data); 
    CFRelease(ref); 
    CFRelease(colorspace); 
    CGImageRelease(iref); 
} 

Cuối cùng, để lấy ảnh chụp màn hình bạn sử dụng renderInContext trong thông thường fasion. Tất nhiên, cái đẹp là bạn không cần phải lấy trực tiếp chế độ xem OpenGL. Bạn có thể lấy một trong những superviews của quan điểm OpenGL và có được một ảnh chụp màn hình sáng tác bao gồm các quan điểm OpenGL cùng với bất cứ điều gì khác bên cạnh nó hoặc trên đầu trang của nó:

UIGraphicsBeginImageContextWithOptions(superviewToGrab.bounds.size, YES, 0); 
CGContextRef context = UIGraphicsGetCurrentContext(); 
[superviewToGrab.layer renderInContext: context]; // This recursively calls renderInContext on all the sublayers, including your OpenGL layer(s) 
CGImageRef screenShot = UIGraphicsGetImageFromCurrentImageContext().CGImage; 
UIGraphicsEndImageContext(); 
+0

Tôi đang thử cách tiếp cận của bạn nhưng glReadPixels dường như không sao chép bất kỳ dữ liệu nào vào bộ đệm của tôi (biến "dữ liệu" trong ví dụ của bạn). Bất kỳ suy nghĩ nào về lý do tại sao điều này có thể xảy ra? Thiết lập của tôi là UIView thường xuyên có lớp sao lưu là CAEAGLLayer. Sau đó tôi thêm một UIImageView với một hình ảnh như là một đứa trẻ của chế độ xem GL-backed. Sau đó, tôi cố gắng lấy nội dung renderBuffer và bộ đệm của tôi vẫn là tất cả 0 như khi tôi khởi tạo nó với calloc. Tôi cũng đã cố gắng thiết lập lớp như là bộ lưu trữ renderbuffer nhưng không có gì. Nếu tôi thực hiện renderInContext thông thường, tôi sẽ lấy lại nội dung dưới dạng hình ảnh. – SaldaVonSchwartz

0

Tôi nghĩ rằng http://developer.apple.com/library/ios/#qa/qa1704/_index.html cung cấp những gì bạn muốn.

+0

Cảm ơn bạn đã trả lời. Tôi có hai cái nhìn opengl (kết cấu) một cái khác. Tôi cần phải nắm bắt được kết quả của hai quan điểm. Tôi không chắc lắm, nếu con trỏ giúp tôi có được những gì tôi muốn. – user862972

+0

Hai họa tiết được vẽ theo hai ngữ cảnh khác nhau. – user862972

+0

Chỉ cần thực thi mã một lần cho mỗi ngữ cảnh, sau đó tổng hợp hai hình ảnh thành một khi bạn cần. – MrMage

1

Câu hỏi này đã được giải quyết, nhưng tôi muốn lưu ý rằng câu trả lời của Idoogy thực sự nguy hiểm và là một lựa chọn không tốt cho hầu hết các trường hợp sử dụng.

Thay vì lớp con CAEAGLLayer và tạo đối tượng đại biểu mới, bạn có thể sử dụng phương thức ủy quyền hiện có hiện có hoàn thành chính xác điều tương tự. Ví dụ:

- (void) drawLayer:(CALayer *) layer inContext:(CGContextRef)ctx; 

là một phương pháp tuyệt vời để triển khai trong chế độ xem dựa trên GL của bạn. Bạn có thể thực hiện nó theo cùng cách mà anh ta gợi ý, sử dụng glReadPixels: chỉ cần đảm bảo đặt thuộc tính Retained-Backing trên view của bạn thành YES, để bạn có thể gọi phương thức trên bất cứ lúc nào mà không phải lo lắng về nó. trình bày để hiển thị.

Phân lớp lớp CAEAGL lộn xộn với mối quan hệ đại biểu UIView/CALayer hiện có: trong hầu hết các trường hợp, đặt đối tượng đại biểu trên lớp tùy chỉnh của bạn sẽ dẫn đến UIView của bạn bị loại trừ khỏi hệ thống phân cấp chế độ xem. Do đó, mã như sau:

customLayerView = [[CustomLayerView alloc] initWithFrame:someFrame]; 
[someSuperview addSubview:customLayerView]; 

sẽ dẫn đến mối quan hệ cận cảnh giám sát một cách kỳ lạ, vì phương thức ủy nhiệm mà UIView dựa vào sẽ không được triển khai. (Superview của bạn sẽ vẫn có sublayer từ xem tùy chỉnh của bạn, mặc dù).

Vì vậy, thay vì phân lớp CAEAGLLayer, chỉ cần triển khai một số phương thức đại biểu. Táo đẻ nó ra cho bạn ở đây: https://developer.apple.com/library/ios/documentation/QuartzCore/Reference/CALayerDelegate_protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40012871

All the best,

Sam

+0

Tôi sẽ đăng một phản ứng muộn với điều này: Phân lớp CAEAGLLayer là hoàn toàn an toàn và sẽ dẫn đến hành vi giống hệt 100%. Đó là bởi vì cách mà chúng ta phân lớp CAEAGLLayer không phải bằng cách tự khởi tạo nó với lớp riêng của chúng ta, mà là cung cấp lớp như lớpClass cho UIView (trong đó, nếu bạn đọc câu trả lời của tôi, bạn sẽ thấy là phương pháp mà tôi đề nghị) . Điều này đảm bảo rằng khởi tạo được thực hiện bởi hệ thống, và vì vậy tất cả mọi thứ là chính xác như nó sẽ có được mà không có lớp con, đại biểu và tất cả. – ldoogy

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