出现"renderincontext"问题.带有opengl视图 [英] Issue with "renderincontext" with opengl views

查看:64
本文介绍了出现"renderincontext"问题.带有opengl视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用openGL视图时遇到问题.我有两个openGL视图.第二个视图作为子视图添加到主视图.这两个opengl视图是在两个不同的opengl上下文中绘制的.我需要用两个opengl视图捕获屏幕.

I have a problem, with openGL views. I have two openGL views. The second view is added as a subview to the mainview. The two opengl views are drawn in two different opengl contexts. I need to capture the screen with the two opengl views.

问题是,如果我尝试在如下上下文中渲染一个CAEAGLLayer:

The issue is that if I try to render one CAEAGLLayer in a context as below:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 1*(self.frame.size.width*0.5), 1*(self.frame.size.height*0.5));
CGContextScaleCTM(context, 3, 3);
CGContextTranslateCTM(context, abcd, abcd);

CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.myOwnView.layer;
[eaglLayer renderInContext:context];

它不起作用.如果我看到上下文(将输出显示为图像),则缺少opengl层中的内容.但是我在输出图像中找到了工具栏和附加到视图的2d图像.我不确定这个问题.请帮忙.

it does not work. If I see the context (given the output as an image), The contents in the opengl layer are missing. But I find the toolbar and 2d images attached to the view, in the output image. I am not sure of the problem. Please help.

推荐答案

我遇到了类似的问题,并且找到了更为优雅的解决方案.基本上,您可以继承CAEAGLLayer的子类,并添加自己的renderInContext实现,该实现只要求OpenGL视图使用glReadPixels呈现内容.妙处在于,现在您可以在层次结构的任何层上调用renderInContext,并且结果是一个完全组成的,外观完美的屏幕截图,其中包括您的OpenGL视图!

I had a similar problem and found a much more elegant solution. Basically, you subclass CAEAGLLayer, and add your own implementation of renderInContext that simply asks the OpenGL view to render the contents using glReadPixels. The beauty is that now you can call renderInContext on any layer in the hierarchy, and the result is a fully composed, perfect looking screenshot that includes your OpenGL views in it!

在子类CAEAGLLayer中的renderInContext是:

Our renderInContext in the subclassed CAEAGLLayer is:

- (void)renderInContext:(CGContextRef)ctx
{
    [super renderInContext: ctx];
    [self.delegate renderInContext: ctx];
}

然后,在OpenGL视图中,我们替换layerClass,以便它返回我们的子类,而不是普通的CAEAGLLayer:

Then, in the OpenGL view we replace layerClass so that it returns our subclass instead of the plain vanilla CAEAGLLayer:

+ (Class)layerClass
{
    return [MyCAEAGLLayer class];
}

我们在视图中添加了一个方法,以将视图的内容实际呈现到上下文中.请注意,此代码必须在渲染GL视图之后但在调用 presentRenderbuffer 之前运行,以便渲染缓冲区将包含您的帧.否则,生成的图像很可能是空白的(您可能会在此特定问题上看到设备和模拟器之间的不同行为).

We add a method in the view to actually render the contents of the view into the context. Note that this code MUST run after your GL view has been rendered, but before you call presentRenderbuffer so that the render buffer will contain your frame. Otherwise the resulting image will most likely be empty (you may see different behavior between the device and the simulator on this particular issue).

- (void) renderInContext: (CGContextRef) context
{
    GLint backingWidth, backingHeight;

    // Bind the color renderbuffer used to render the OpenGL ES view
    // If your application only creates a single color renderbuffer which is already bound at this point,
    // this call is redundant, but it is needed if you're dealing with multiple renderbuffers.
    // Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class.
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);

    // Get the size of the backing CAEAGLLayer
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &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);

    CGFloat scale = self.contentScaleFactor;
    NSInteger widthInPoints, heightInPoints;
    widthInPoints = width / scale;
    heightInPoints = height / scale;

    // 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(context, kCGBlendModeCopy);
    CGContextDrawImage(context, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);

    // Clean up
    free(data);
    CFRelease(ref);
    CFRelease(colorspace);
    CGImageRelease(iref);
}

最后,为了获取屏幕快照,您可以在通常的方式中使用renderInContext.当然,美丽之处在于您无需直接获取OpenGL视图.您可以获取OpenGL视图的超级视图之一,并获得包含OpenGL视图以及其旁边或顶部的其他所有内容的合成屏幕截图:

Finally, in order to grab a screenshot you use renderInContext in the usual fasion. Of course the beauty is that you don't need to grab the OpenGL view directly. You can grab one of the superviews of the OpenGL view and get a composed screenshot that includes the OpenGL view along with anything else next to it or on top of it:

UIGraphicsBeginImageContextWithOptions(superviewToGrab.bounds.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[superviewToGrab.layer renderInContext: context]; // This recursively calls renderInContext on all the sublayers, including your OpenGL layer(s)
CGImageRef screenShot = UIGraphicsGetImageFromCurrentImageContext().CGImage;
UIGraphicsEndImageContext();

这篇关于出现"renderincontext"问题.带有opengl视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆