2010-11-07 16 views

risposta

19

È possibile utilizzare la proprietà layer della vista per ottenere il CALayer e utilizzare renderInContext: su quello per disegnare in un contesto CoreGraphics. È possibile impostare un contesto CoreGraphics con memoria allocata dall'utente per ricevere un buffer di pixel. È quindi possibile caricarlo in OpenGL con il metodo normale.

Quindi: c'è un mezzo per ottenere il contenuto dei pixel di un UIView e OpenGL accetterà i buffer dei pixel. Non esiste un collegamento specifico tra i due.

Coding estemporaneamente, il processo sarebbe qualcosa di simile:

UIView *view = ... something ...; 

// make space for an RGBA image of the view 
GLubyte *pixelBuffer = (GLubyte *)malloc(
           4 * 
           view.bounds.size.width * 
           view.bounds.size.height); 

// create a suitable CoreGraphics context 
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); 
CGContextRef context = 
    CGBitmapContextCreate(pixelBuffer, 
          view.bounds.size.width, view.bounds.size.height, 
          8, 4*view.bounds.size.width, 
          colourSpace, 
          kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
CGColorSpaceRelease(colourSpace); 

// draw the view to the buffer 
[view.layer renderInContext:context]; 

// upload to OpenGL 
glTexImage2D(GL_TEXTURE_2D, 0, 
      GL_RGBA, 
      view.bounds.size.width, view.bounds.size.height, 0, 
      GL_RGBA, GL_UNSIGNED_BYTE, pixelBuffer); 

// clean up 
CGContextRelease(context); 
free(pixelBuffer); 

che non si occupa di questioni che circondano non-potere-su-due viste dimensioni su hardware senza il non-potere-di-due tessitura estensione e presuppone che un nome di struttura GL appropriato sia già stato generato e vincolato. Controllate voi stessi, ma penso che il non-potere-di-due sia supportato sull'hardware SGX (cioè, iPhone 3GS in poi, l'iPad e tutti tranne l'iPod Touch di terza generazione da 8 gb in poi) ma non su MBX.

Il modo più semplice per gestire le trame non di potenza di due è probabilmente quello di creare una grande potenza di due texture e di usare glTexSubImage2D per caricare solo la porzione dalla tua UIView di origine.

+0

Utilizzo di CVOpenGLESTextureCacheCreateTextureForImage deve essere più efficiente dell'utilizzo di glTexImage2D direttamente. Il buffer dei pixel dovrebbe avere le chiavi 'IOSurfaceProperties' e' OpenGLESCompatibility' definite. – OrangeDog

5

Ecco un altro metodo per afferrare un livello OpenGL, che è quello di utilizzare glReadPixels. Questo catturerà i livelli visibili DIETRO il tuo livello openGL, (in sostanza, lo schermo visibile). Dai un'occhiata a questa domanda: How do I grab an image form my EAGLLayer ?

Una volta che hai la tua immagine, deve essere ridimensionata alla potenza di due. Puoi provare e allungare l'immagine, ma ciò causerà problemi di qualità quando lo riduci di nuovo o se lo fai più volte. Il modo migliore è disegnare la dimensione normale dell'immagine in una trama di base-2 con extra pixel per creare un buffer. Ecco il codice (ho modificato questo dal codice di qualcun altro, ma non riesco a trovare il codice originale, quindi se qualcuno vede il codice originale, per favore fatemelo sapere da dove è venuto a dare credito):

-(UIImage*)base2Image:(UIImage *) srcImg { 
    int frame2Base = 512; 

    CGSize srcSize = [srcImg size]; 
    CGRect rec = CGRectMake(0, 0, frame2Base, frame2Base); 

    [srcImg drawInRect:rec blendMode:kCGBlendModeNormal alpha:1.0]; 

    //create a context to do our clipping in 
    UIGraphicsBeginImageContext(CGSizeMake(frame2Base, frame2Base)); 
    CGContextRef currentContext = UIGraphicsGetCurrentContext(); 

    //create a rect with the size we want to crop the image to 
    CGRect clippedRect = CGRectMake(0, 0, frame2Base, frame2Base); 
    CGContextClipToRect(currentContext, clippedRect); 

    //create a rect equivalent to the full size of the image 
    CGRect drawRect = CGRectMake(0, 0, srcSize.width, srcSize.height); 

    //draw the image to our clipped context using our offset rect 
    CGContextDrawImage(currentContext, drawRect, srcImg.CGImage); 

    UIImage *dstImg = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return dstImg; 
} 

Ora, una volta fatto, si utilizza una matrice di coordinate di trama per SOLO estrarre la sezione di dimensioni corrette dall'immagine. Ad esempio:

GLfloat texCoords[] = { 
    0.0, (float)frameHeight/2BaseHeight, 
    0.0, 0.0, 
    (float)frameWidth/2BaseWidth, (float)frameHeight/2BaseHeight, 
    (float)frameWidth/2BaseWidth, 0.0 
}; 

E ce l'hai. Uno screenshot dal tuo schermo visibile che ora è una texture.

+0

Questa è una grande tecnica! In realtà ho bisogno di ottenere solo il contenuto di una porzione della mia gerarchia di visualizzazione, ma ancora, +1. –

Problemi correlati