2012-02-27 18 views
10

Tengo un montón de dificultades al tomar una instantánea de UIImage de una vista controlada de Isgl3d. Parece que todo lo que hago, acabo con un cuadrado negro.Captura de la salida de Isgl3d como imagen

Tengo una vista de cámara de trabajo y un modelo 3d en mi opinión, intento con ambos métodos de buffer y capturas de pantalla regulares para obtener una imagen de ella, pero sin ningún resultado fructífero.

¿Alguien tiene algún código fuente donde toma una foto de una vista Isgl3d correctamente?

Respuesta

5

Aquí están las instrucciones de Apple & código oficial para capturar una vista GL a UIImage (tiene en cuenta las pantallas retina, flipped coords, etc.) y la he estado usando con éxito. Esto no es específico de iSGL3D, por supuesto, pero mientras puedas obtener el contexto y framebuffer correctos para enlazar, debería hacer lo correcto. (Como las notas de páginas, debe estar seguro de tomar la instantánea antes de que un -presentRenderbuffer: se llama por lo que el renderbuffer es válida.)

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

que sólo tienen una familiaridad superficial con la biblioteca iSGL3D, y que doesn' Parece que hay ganchos obvios para que pueda renderizar la escena pero no para presentarla (o para renderizarla primero en un buffer fuera de la pantalla). El lugar donde podría necesitar intervenir es en el método -finalizeRender de la subclase Isgl3dGLContext que está utilizando, justo antes de llamar a la llamada -presentRenderbuffer. Ese contexto es una clase de marco interno aquí, por lo que puede necesitar reorganizar un poco las cosas dentro de la biblioteca para configurar (por ejemplo) un delegado del contexto que funciona fuera de la vista y el director para eventualmente pedirle a su aplicación realice cualquier acción justo antes de la llamada "presente", durante la cual puede elegir ejecutar el código de captura de pantalla si lo desea, o no hacer nada si no lo desea.

3

¿Esto es lo que quieres?

Esto tomará una captura de pantalla del contexto actual y framebuffer y lo guardará en el álbum de fotos.

Si no desea guardar en el álbum de fotos solo obtenga el UIImage resultante al final.

Recuerde también llamar a esto solo después de que haya terminado de dibujar, pero antes de cambiar de buffers.

Además, si usa MSAA, debe invocarse después de que glResolveMultisampleFramebufferAPPLE y el nuevo búfer se vinculen.

#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 

que utiliza este código para guardar imágenes cronometrados mientras estoy jugando, así que tengo material de dios para poner en la tienda de aplicaciones.

3

Utilizo este fragmento de código con éxito en una de mis aplicaciones para hacer capturas de pantalla de 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]; 
} 

Asegúrese de que ates el registro de cuadro antes de hacer esto, al igual que

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

Y llama -glToUIImage antes de presentar el registro de cuadro!

Para obtener más información, Apple proporciona sample code para tomar capturas de pantalla de OpenGL.

+0

Parece útil, pero ¿de dónde obtienes tus valores rojo, verde y azul? –

+0

Eso es solo una enumeración para nombrar las compensaciones (0, 1, 2, 3), se olvidó de agregar esto aquí. Actualizado el fragmento. –

2

Se me ocurre esta posible solución. Tienes que modificar un poco la biblioteca de isgl3d.

Los pasos son:

1.

Crear delegado de Isgl3dGLContext1:

En 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.

. Añadir este código a Isgl3dGLContext1.m:

@synthesize takePicture; 
@synthesize colorRenderBuffer = _colorRenderBuffer; 

Antes de línea [_context presentRenderbuffer: GL_RENDERBUFFER_OES]; en - (void) finalizeRender:

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

3 poner este código en la clase en la que desea tomar captura de pantalla:

In Class.h add <ScreenShooterDelegate> 

En el método 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; 

En el método - (void) takePicture {} Pon el código de Apple y al final del método agrega [Isgl3dDirector sharedInstance] .antiAliasingEnabled = YES; (En caso de que si lo usa)

//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: Para mí funcionaba comentando glBindRenderbufferOES (GL_RENDERBUFFER_OES, _colorRenderbuffer); y En su caso, puede hacer estos pasos con Isgl3dGLContext2 en lugar de Isgl3dGLContext1.

Cuestiones relacionadas