将UIView的内容渲染为OpenGL纹理

Hil*_*ell 12 iphone opengl-es uiview

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

Tom*_*mmy 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);
Run Code Online (Sandbox Code Playgroud)

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

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


Bea*_*ker 5

这是获取OpenGL Layer的另一种方法,即使用glReadPixels.这将抓住你的openGL层后面的可见层(基本上,你的可见屏幕).看看这个问题: 如何从我的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;
}
Run Code Online (Sandbox Code Playgroud)

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

GLfloat texCoords[] = {
    0.0, (float)frameHeight/2BaseHeight,
    0.0, 0.0,
    (float)frameWidth/2BaseWidth, (float)frameHeight/2BaseHeight,
    (float)frameWidth/2BaseWidth, 0.0
};
Run Code Online (Sandbox Code Playgroud)

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