iOS上使用多重采样的glReadPixels技术问题

3
我正在尝试从带有多重采样的帧缓冲区获取像素。但是它只返回零。我按照这里这里建议的方式调用glResolveMultisampleFramebufferAPPLE,但我无法弄清楚我的情况出了什么问题。
首先,我创建了一个具有颜色附件的非多重采样帧缓冲区:
GLuint framebuffer, colorRenderbuffer;

glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);

glGenRenderbuffersOES(1, &colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, w, h);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

然后创建多重采样帧缓冲区,并附加颜色和深度。
GLuint sampleFramebuffer, sampleColorRenderbuffer, sampleDepthRenderbuffer;

glGenFramebuffersOES(1, &sampleFramebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, sampleFramebuffer);

glGenRenderbuffersOES(1, &sampleColorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_RGBA8_OES, w, h);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, sampleColorRenderbuffer);

glGenRenderbuffersOES(1, &sampleDepthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_DEPTH_COMPONENT16_OES, w, h);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, sampleDepthRenderbuffer);

清除帧缓冲区:

glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glClear(GL_COLOR_BUFFER_BIT);

glBindFramebufferOES(GL_FRAMEBUFFER_OES, sampleFramebuffer);
glViewport(0, 0, w, h);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

我来翻译一下(这是Cocos3D绘图代码):

[cc3Layer visit];

然后解决缓冲区:
glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, framebuffer);
glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
glResolveMultisampleFramebufferAPPLE();

glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, framebuffer);

然后获取所有的零:

glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);

我在创建帧缓冲时跳过了两个检查,因为它们已经成功创建。我的代码出了什么问题?


你不会正在使用discard吧? - Justin Meiners
@JustinMeiners我当然会这样做,但据我所知,这一步仅适用于性能问题。改进不起作用的代码的性能是否有理由呢? :) 另外,它是在glReadPixels和glBindRenderbuffer之后进行的,对吗? - medvedNick
2个回答

1

在读取像素之前,您应该先绑定非多重采样颜色渲染缓冲区。

如下所示:

glResolveMultisampleFramebufferAPPLE()
glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, framebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

谢谢回答,但那个绑定并不是必要的。我会更新问题以展示可工作的代码。 - medvedNick

0
问题不在OpenGL中,而是在Cocos3d渲染中(-visit没有设置一些绘图属性,但-drawScene设置了)。这是可行的代码:
+(UIImage*) takeScreenshotFromScreenRect:(CGRect)rect withResultSize:(CGSize)outSize
{
    CCDirector *director = [CCDirector sharedDirector];
    director.nextDeltaTimeZero = YES;

    rect.origin.x *= CC_CONTENT_SCALE_FACTOR();
    rect.origin.y *= CC_CONTENT_SCALE_FACTOR();
    rect.size.width *= CC_CONTENT_SCALE_FACTOR();
    rect.size.height *= CC_CONTENT_SCALE_FACTOR();

    int w = rect.size.width;
    int h = rect.size.height;

    int winW = director.winSizeInPixels.width;
    int winH = director.winSizeInPixels.height;

    GLuint bufferLength = w * h * 4;
    GLubyte* buffer = (GLubyte*)malloc(bufferLength);

    [director pause];

    static GLuint framebuffer = 0, colorRenderbuffer;
    static GLuint sampleFramebuffer, sampleColorRenderbuffer, sampleDepthRenderbuffer;

    if (framebuffer == 0)
    {
        glGenFramebuffersOES(1, &framebuffer);
        glGenRenderbuffersOES(1, &colorRenderbuffer);
        glGenFramebuffersOES(1, &sampleFramebuffer);
        glGenRenderbuffersOES(1, &sampleColorRenderbuffer);
        glGenRenderbuffersOES(1, &sampleDepthRenderbuffer);
    }

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, winW, winH);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, sampleFramebuffer);

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, sampleColorRenderbuffer);
    glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, director.openGLView.pixelSamples, GL_RGBA8_OES, winW, winH);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, sampleColorRenderbuffer);


    glBindRenderbufferOES(GL_RENDERBUFFER_OES, sampleDepthRenderbuffer);
    glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, director.openGLView.pixelSamples, GL_DEPTH_COMPONENT16_OES, winW, winH);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, sampleDepthRenderbuffer);

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(150.0/255, 190.0/255, 255.0/255, 1);

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, sampleFramebuffer);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(150.0/255, 190.0/255, 255.0/255, 1);

    [director drawScene];

    glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, framebuffer);
    glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
    glResolveMultisampleFramebufferAPPLE();

    glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, framebuffer);

    glReadPixels(rect.origin.x, rect.origin.y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    GLenum attachments[] = {GL_COLOR_ATTACHMENT0_OES, GL_DEPTH_ATTACHMENT_OES};
    glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments);

        // restoring render buffers from cocos

    ES1Renderer *renderer = [[CCDirector sharedDirector].openGLView valueForKey:@"renderer_"];

    glBindFramebuffer(GL_FRAMEBUFFER_OES, renderer.msaaFrameBuffer);
    glBindFramebuffer(GL_RENDERBUFFER_OES, renderer.msaaColorBuffer);


    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL);

    [director resume];


    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * w;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    CGImageRef iref = CGImageCreate(w, h, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    uint32_t* pixels = (uint32_t*)malloc(bufferLength);
    CGContextRef context = CGBitmapContextCreate(pixels, outSize.width, outSize.height, 8, outSize.width * 4, CGImageGetColorSpace(iref), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextTranslateCTM(context, 0, outSize.height);
    CGContextScaleCTM(context, 1.0f, -1.0f);

    switch (director.deviceOrientation)
    {
        case CCDeviceOrientationPortrait:
            break;
        case CCDeviceOrientationPortraitUpsideDown:
            CGContextRotateCTM(context, CC_DEGREES_TO_RADIANS(180));
            CGContextTranslateCTM(context, -outSize.width, -outSize.height);
            break;
        case CCDeviceOrientationLandscapeLeft:
            CGContextRotateCTM(context, CC_DEGREES_TO_RADIANS(-90));
            CGContextTranslateCTM(context, -outSize.height, 0);
            break;
        case CCDeviceOrientationLandscapeRight:
            CGContextRotateCTM(context, CC_DEGREES_TO_RADIANS(90));
            CGContextTranslateCTM(context, outSize.width * 0.5f, -outSize.height);
            break;
    }

    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, outSize.width, outSize.height), iref);
    CGImageRef imageFromContext = CGBitmapContextCreateImage(context);
    UIImage *outputImage = [UIImage imageWithCGImage:imageFromContext];

    CGDataProviderRelease(provider);
    CGImageRelease(iref);
    CGContextRelease(context);
    free(buffer);
    free(pixels);

    return outputImage;
}

谢谢。我刚刚测试了一下:glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); 在我的渲染引擎中不是可选的。也许是因为它使用了OpenGL ES2上下文...或者我永远不会知道! - Vivien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接