2012-02-27 15 views
10

Isl3dで制御されたビューのUIImageスナップショットを作成するのが難しいです。私が何をしていても、私はちょうど黒い四角で終わる。画像としてのIsgl3d出力のキャプチャ

私は自分の見解では動作するカメラビューと3Dモデルを持っていますが、私はバッファメソッドと通常のスクリーンキャプチャを使って画像を取得しようとしましたが、何の成果もありませんでした。

誰かがIsgl3dビュ​​ーの画像を正常に撮影するソースコードを持っていますか?

答えて

5

アップルの指示&は、GLビューをUIImageにスナップショットするための公式のコードです(網膜の表示、反転した指などを考慮しています)。もちろんこれはiSGL3D固有のものではありませんが、適切なコンテキストとフレームバッファをバインドすることができれば、正しいことを行うはずです。 (ページノートとして、あなたはレンダが有効であるよう-presentRenderbuffer:が呼び出される前に、スナップショットを取ることを確認する必要があります。)

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

「私はiSGL3Dライブラリとだけザッと親しみを持っており、それはdoesnのシーンをレンダリングさせるが、それを表示させない(または、オフスクリーンのバッファーに最初にレンダリングする)ための明白なフックがあるように見えません。介入する必要がある場所は、-presentRenderbuffer呼び出しの直前に、使用しているIsgl3dGLContextサブクラスの-finalizeRenderメソッドです。そのコンテキストはここの内部フレームワーククラスです。したがって、ライブラリ内のものをちょっとシャッフルして、ビューから戻ってくるコンテキストからデリゲートを設定して、最終的にはあなたのアプリにあなたがしたい場合はスクリーンショットコードを実行するか、そうしたくない場合は何もしないようにすることができます。

3

これは必要なものですか?

これは、現在のコンテキストとフレームバッファからスクリーンショットを取り、それをフォトアルバムに保存します。

あなただけの最後に結果のUIImageを取得し、フォトアルバムに保存したくない場合。

描画を終了してからバッファを切り替える前にこの関数を呼び出すことも忘れないでください。あなたはMSAAを使用している場合

はまた、これはglResolveMultisampleFramebufferAPPLEと新しいバッファのバインド後に呼び出される必要があります。私はアプリストアに置くために神の材料を持っているので、プレイしてる間、私は時限式のスクリーンショットを保存するには、このコードを使用し

#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 

3

このコードスニペットは、私のアプリケーションの1つで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]; 
} 

ので

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

のように、あなたがこれを行う前に、フレームバッファをバインドしていることを確認して、フレームバッファが提示される前-glToUIImageを呼びます!さらに詳しい情報については、アップル

は、OpenGLのスクリーンショットを取るためsample codeを提供します。

+0

見た目は便利ですが、赤、緑、青の値はどこから得られますか? –

+0

オフセット(0,1,2,3)に名前を付けるだけの列挙型なので、ここにこれを追加するのを忘れてしまった。スニペットを更新しました。 –

2

私はこの可能な解決策を考え出します。 isgl3dのライブラリを少し修正する必要があります。

手順は次のとおりです。

1.

がIsgl3dGLContext1のためのデリゲートを作成します。

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.

。 Isgl3dGLContext1.mにこのコードを追加します。

@synthesize takePicture; 
@synthesize colorRenderBuffer = _colorRenderBuffer; 

ラインの前に[presentRenderbuffer _context:GL_RENDERBUFFER_OES];中 - (無効)finalizeRender:

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

3入れ、このコードあなたはスクリーンショットを撮りたいクラスで:メソッドで

In Class.h add <ScreenShooterDelegate> 
方法で

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; 

- (void)takePicture {} Appleのコードを入れ、メソッドの最後に[Isgl3dDirector sharedInstance]を追加します.antiAliasingEnabled = YES;注

//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; 
} 

(あなたがそれを使用する場合場合):私にとってはちょうどコメントglBindRenderbufferOES(GL_RENDERBUFFER_OES、_colorRenderbuffer)を働きました。および 場合によっては、Isgl3dGLContext1ではなくIsgl3dGLContext2でこれらの手順を実行できます。

関連する問題