glReadPixels на iOS с мультисэмплингом

Я пытаюсь получить пиксели из фреймбуфера с мультисэмплингом. Возвращает только нули. Я вызываю 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);

Я пропустил две проверки gl на успешность создания фреймбуфера, так как они успешно создаются. Где ошибка в моем коде?


person medvedNick    schedule 29.07.2013    source источник
comment
Вы случайно не используете сброс, не так ли?   -  person Justin Meiners    schedule 29.07.2013
comment
@JustinMeiners Конечно, я бы хотел, но, насколько я понимаю, этот шаг предназначен только для решения проблем с производительностью. Есть ли причина улучшать производительность неработающего кода? :) Кроме того, он сделан после glReadPixels и glBindRenderbuffer, я прав?   -  person medvedNick    schedule 29.07.2013


Ответы (2)


Вы должны привязать не мультисэмпловый буфер рендеринга цвета ПЕРЕД чтением пикселей.

как это:

glResolveMultisampleFramebufferAPPLE()
glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, framebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
person Vivien    schedule 01.09.2013
comment
спасибо за ответ, но эта привязка не нужна. Я обновлю вопрос, чтобы показать рабочий код - person medvedNick; 02.09.2013

проблема была не в 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;
}
person medvedNick    schedule 02.09.2013
comment
Спасибо. Я просто тестирую: glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); не является факультативным с моим движком рендеринга. Может быть, потому что он использует контекст opengl ES2... или я никогда не узнаю! - person Vivien; 05.09.2013