2012-02-27 11 views
10

Sto riscontrando una serie di difficoltà nell'ottenere un'istantanea UIImage di una vista controllata da Isgl3d. Sembra che qualunque cosa io faccia, finisco con un quadrato nero.Catturare l'output di Isgl3d come immagine

Ho una vista funzionante della fotocamera e un modello 3d a mio avviso, provo con entrambi i metodi di buffer e le normali acquisizioni dello schermo per ricavarne un'immagine, ma senza risultati fruttuosi.

Qualcuno ha qualche codice sorgente in cui è possibile scattare una foto di una vista Isgl3d?

risposta

5

Ecco le istruzioni di Apple & codice ufficiale per l'istantanea di una vista GL su un UIImage (tiene conto di display retina, cordoli capovolti, ecc.) E l'ho usato con successo. Questo non è specifico per iSGL3D, naturalmente, ma finché si può ottenere il contesto e il framebuffer corretti da associare, dovrebbe fare la cosa giusta. (Come le note di pagina, è necessario essere sicuri di prendere l'istantanea prima di un -presentRenderbuffer: si chiama così la renderbuffer è valido.)

https://developer.apple.com/library/ios/#qa/qa1704/_index.html

ho solo una familiarità superficiale con la libreria iSGL3D, e doesn' Sembra che ci siano degli hook ovvi per permetterti di renderizzare la scena ma non di presentarla (o prima di renderla a un buffer fuori dallo schermo). Il luogo in cui potrebbe essere necessario intervenire è il metodo -finalizeRender della sottoclasse Isgl3dGLContext che si sta utilizzando, appena prima della chiamata alla chiamata -presentRenderbuffer. Quel contesto è una classe quadro interna qui, quindi potrebbe essere necessario rimescolare le cose un po 'all'interno della libreria per impostare (diciamo) un delegato dal contesto che lavora fuori dalla vista e il regista per chiedere eventualmente alla tua app di prendere qualsiasi azione appena prima della chiamata "presente", durante la quale è possibile scegliere di eseguire il codice dello screenshot se si desidera, o non fare nulla se non si desidera.

3

È questo quello che vuoi?

Questo richiederà uno screenshot dal contesto corrente e dal framebuffer e lo salverà nell'album fotografico.

Se non si desidera salvare nell'album fotografico, ottenere la UIImage risultante alla fine.

Ricordare anche di chiamare questo solo dopo aver finito di disegnare, ma prima di passare ai buffer.

Anche se si utilizza MSAA, questo deve essere chiamato dopo glResolveMultisampleFramebufferAPPLE e il nuovo binding del buffer.

#ifdef AUTOSCREENSHOT 

// callback for CGDataProviderCreateWithData 
void releaseData(void *info, const void *data, size_t dataSize) { 
    free((void*)data); 
} 

// callback for UIImageWriteToSavedPhotosAlbum 
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 
    NSLog(@"Save finished"); 
    [image release]; 
} 

-(void)saveCurrentScreenToPhotoAlbum { 
    int height = (int)screenSize.y*retina; 
    int width = (int)screenSize.x*retina; 

    NSInteger myDataLength = width * height * 4; 
    GLubyte *buffer = (GLubyte *) malloc(myDataLength); 
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength); 
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 
    for(int y = 0; y <height; y++) { 
     for(int x = 0; x < width * 4; x++) { 
      buffer2[(int)((height - 1 - y) * width * 4 + x)] = buffer[(int)(y * 4 * width + x)]; 
     } 
    } 
    free(buffer); 

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, releaseData); 
    int bitsPerComponent = 8; 
    int bitsPerPixel = 32; 
    int bytesPerRow = 4 * width; 
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; 
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; 
    CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); 

    CGColorSpaceRelease(colorSpaceRef); 
    CGDataProviderRelease(provider); 

    UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 

    UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 
} 

#endif 

Io uso questo codice per salvare gli screenshot cronometrati mentre sto giocando quindi devo materiale dio mettere in App Store.

3

Uso lo snippet di codice in una delle mie app per eseguire schermate OpenGL.

enum { 
    red, 
    green, 
    blue, 
    alpha 
}; 

- (UIImage *)glToUIImage { 
    CGSize glSize = self.glView.bounds.size; 
    NSInteger bufDataLen = glSize.width * glSize.height * 4; 

    // Allocate array and read pixels into it. 
    GLubyte *buffer = (GLubyte *)malloc(bufDataLen); 
    glReadPixels(0, 0, glSize.width, glSize.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 

    // We need to flip the image 
    NSUInteger maxRow = (NSInteger)glSize.height - 1; 
    NSUInteger bytesPerRow = (NSInteger)glSize.width * 4; 

    GLubyte *buffer2 = (GLubyte *)malloc(bufDataLen); 
    for(int y = maxRow; y >= 0; y--) { 
    for(int x = 0; x < bytesPerRow; x+=4) { 
     NSUInteger c0 = y * bytesPerRow + x; 
     NSUInteger c1 = (maxRow - y) * bytesPerRow + x; 
     buffer2[c0+red] = buffer[c1+red]; 
     buffer2[c0+green] = buffer[c1+green]; 
     buffer2[c0+blue] = buffer[c1+blue]; 
     buffer2[c0+alpha] = buffer[c1+alpha]; 
    } 
    } 
    free(buffer); 

    // Make data provider with data 
    CFDataRef imageData = CFDataCreate(NULL, buffer2, bufDataLen); 
    free(buffer2); 

    CGDataProviderRef provider = CGDataProviderCreateWithCFData(imageData); 
    CFRelease(imageData); 

    // Bitmap format 
    int bitsPerComponent = 8; 
    int bitsPerPixel = 32; 
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast; 
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; 

    // Create the CGImage 
    CGImageRef imageRef = CGImageCreate(glSize.width, 
             glSize.height, 
             bitsPerComponent, 
             bitsPerPixel, 
             bytesPerRow, 
             colorSpaceRef, 
             bitmapInfo, 
             provider, 
             NULL, 
             NO, 
             renderingIntent); 

    // Clean up 
    CGColorSpaceRelease(colorSpaceRef); 
    CGDataProviderRelease(provider); 

    // Convert to UIImage 
    UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 

    return [image autorelease]; 
} 

Assicurarsi si associa il frame buffer prima di fare questo, in questo modo

glBindFramebufferOES(GL_FRAMEBUFFER_OES, myFrameBuffer); 
glViewport(0, 0, myBackingWidth, myBackingHeight); 

E chiami -glToUIImage prima che il frame buffer è presentato!

Per ulteriori informazioni, Apple fornisce sample code per l'acquisizione di schermate da OpenGL.

+0

Sembra utile, ma da dove vengono visualizzati i valori di rosso, verde e blu? –

+0

Questo è solo un enum per nominare gli offset (0, 1, 2, 3), ha dimenticato di aggiungere questo qui. Aggiornato lo snippet. –

2

Mi viene in mente questa possibile soluzione. Devi modificare un po 'la libreria di isgl3d.

I passi sono:

1.

Creare delegato per Isgl3dGLContext1:

In Isgl3dGLContext1.h

@protocol ScreenShooterDelegate; 

#import <OpenGLES/ES1/gl.h> 
#import <OpenGLES/ES1/glext.h> 
#import "Isgl3dGLContext.h" 

@interface Isgl3dGLContext1 : Isgl3dGLContext { 

    NSObject<ScreenShooterDelegate>* __unsafe_unretained delegate; 

    GLuint _colorRenderBuffer; 
@private 
    EAGLContext * _context; 

    // The OpenGL names for the framebuffer and renderbuffer used to render to this view 
    GLuint _defaultFrameBuffer; 


    GLuint _depthAndStencilRenderBuffer; 
    GLuint _depthRenderBuffer; 
    GLuint _stencilRenderBuffer; 

    // OpenGL MSAA buffers 
    GLuint _msaaFrameBuffer; 
    GLuint _msaaColorRenderBuffer; 

    GLuint _msaaDepthAndStencilRenderBuffer; 
    GLuint _msaaDepthRenderBuffer; 
    GLuint _msaaStencilRenderBuffer; 
} 

- (id) initWithLayer:(CAEAGLLayer *) layer; 
@property (assign) NSObject<ScreenShooterDelegate>* delegate; 
@property BOOL takePicture; 
@property GLuint colorRenderBuffer; 

@end 

@protocol ScreenShooterDelegate 


@optional 

- (void)takePicture; 

@end 

2.

. Aggiungere questo codice Isgl3dGLContext1.m:

@synthesize takePicture; 
@synthesize colorRenderBuffer = _colorRenderBuffer; 

Prima linea [_context presentRenderbuffer: GL_RENDERBUFFER_OES]; a - (void) finalizeRender:

if(takePicture){ 
     takePicture=NO; 
     if([delegate respondsToSelector:@selector(takePicture)]){ 
      [delegate takePicture]; 
     } 
    } 

3 inserire questo codice nella classe in cui si desidera prendere screenshot:

In Class.h add <ScreenShooterDelegate> 

Nel metodo Class.m

[Isgl3dDirector sharedInstance].antiAliasingEnabled = NO; 

Photos3DAppDelegate *appDelegate = (Photos3DAppDelegate *)[[UIApplication sharedApplication] delegate]; 
[appDelegate.inOutSceneView showSphere]; 

Isgl3dEAGLView* eaglview=(Isgl3dEAGLView*)[[Isgl3dDirector sharedInstance] openGLView]; 
Isgl3dGLContext1 * _glContext=(Isgl3dGLContext1*)[eaglview glContext]; 
_glContext.delegate=self; 
_glContext.takePicture=YES; 

Nel metodo - (void) takePicture {} Inserisci il codice da Apple e alla fine del metodo add [Isgl3dDirector sharedInstance] .antiAliasingEnabled = YES; (Nel caso in cui lo si utilizza)

//https://developer.apple.com/library/ios/#qa/qa1704/_index.html 

-(void)takePicture{ 


NSLog(@"Creating Foto"); 

GLint backingWidth, backingHeight; 

Isgl3dEAGLView* eaglview=(Isgl3dEAGLView*)[[Isgl3dDirector sharedInstance] openGLView]; 
//Isgl3dGLContext1 * _glContext=(Isgl3dGLContext1*)[eaglview glContext]; 
//glBindRenderbufferOES(GL_RENDERBUFFER_OES, _glContext.colorRenderBuffer); 

glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); 
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &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); 

// OpenGL ES measures data in PIXELS 
// Create a graphics context with the target size measured in POINTS 
NSInteger widthInPoints, heightInPoints; 
if (NULL != UIGraphicsBeginImageContextWithOptions) { 
    // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration 
    // Set the scale parameter to your OpenGL ES view's contentScaleFactor 
    // so that you get a high-resolution snapshot when its value is greater than 1.0 
    CGFloat scale = eaglview.contentScaleFactor; 
    widthInPoints = width/scale; 
    heightInPoints = height/scale; 
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale); 
} 
else { 
    // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext 
    widthInPoints = width; 
    heightInPoints = height; 
    UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints)); 
} 

CGContextRef cgcontext = UIGraphicsGetCurrentContext(); 

// 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(cgcontext, kCGBlendModeCopy); 
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref); 

// Retrieve the UIImage from the current context 
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 

UIGraphicsEndImageContext(); 

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

UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); 

[Isgl3dDirector sharedInstance].antiAliasingEnabled = YES; 
} 

Nota: Per me ha funzionato solo commentando glBindRenderbufferOES (GL_RENDERBUFFER_OES, _colorRenderbuffer); e Nel tuo caso puoi seguire questi passaggi con Isgl3dGLContext2 invece di Isgl3dGLContext1.

Problemi correlati