将UIView的内容渲染为OpenGL纹理

时间:2010-11-07 17:16:19

标签: iphone uiview opengl-es

有没有办法在iOS中使用OpenGL将UIView的内容渲染为纹理?还是CGLayer的内容?

2 个答案:

答案 0 :(得分:19)

您可以使用视图的图层属性来获取CALayer并使用renderInContext:来绘制CoreGraphics上下文。您可以使用自己分配的内存设置CoreGraphics上下文,以便接收像素缓冲区。然后,您可以通过常规方法将其上传到OpenGL。

所以:有一种方法可以获得UIView的像素内容,OpenGL将接受像素缓冲区。这两者之间没有具体的联系。

即席编码,过程如下:

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);

这不涉及在没有非2次幂纹理扩展的情况下围绕硬件上的非二次幂大小视图的问题,并且假设已经生成并绑定了合适的GL纹理名称。检查一下你自己,但我认为SGX硬件支持非二合一功能(即iPhone 3GS以上,iPad以及除第八代iPod Touch以外的所有硬件),但不支持MBX。

这里处理非幂二纹理的最简单方法可能是创建两个纹理足够大的功能,并使用glTexSubImage2D只上传源UIView中的部分。

答案 1 :(得分:5)

这是获取OpenGL Layer的另一种方法,即使用glReadPixels。这将抓住你的openGL层后面的可见层(基本上,你的可见屏幕)。看看这个问题: How do I grab an image form my EAGLLayer ?

获得图像后,必须将其调整为2的幂。您可以尝试拉伸图像,但是当您再次缩小图像时,或者一次又一次地执行此操作时,这会导致质量问题。最好的方法是将图像正常大小绘制为基础2纹理,并使用额外的像素来制作缓冲区。这是代码(我从别人的代码中修改了这个代码,但我找不到原始代码,所以如果有人看到原始代码,请告诉我它来自哪里来表示赞赏):

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

现在,完成后,您可以使用纹理坐标数组来仅从图像中拉出正确大小的部分。比如这个:

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

你有它。来自可见屏幕的截图,现在是纹理。