Отрисовка вне экрана (с FBO и RenderBuffer) и передача цвета, глубины, трафарета в пикселях

Мне нужно отрисовать за пределами экрана в OpenGL, а затем передать изображение в QImage. Плюс, просто для тренировки я хотел бы перенести в процессор также глубину и буфер трафарета.

Для рисования вне экрана я использовал Frame Buffer Object с Render Buffer (а не с текстурой, потому что мне не нужна текстура).

Пиксельная передача с цветными буферами (фактическое необработанное изображение) работает .. Я вижу то, что я ожидаю. Но глубина и трафарет не работают .. странное изображение для глубины и ничего для трафарета.

Во-первых, самое простое, что я на самом деле рисую:

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(-1.5f,0.0f,-6.0f);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f,0.0f,0.0f);
    glVertex3f( 0.0f, 1.0f, 0.0f);
    glColor3f(0.0f,1.0f,0.0f);
    glVertex3f(-1.0f,-1.0f, -1.0f);
    glColor3f(0.0f,0.0f,1.0f);
    glVertex3f( 1.0f,-1.0f, 0.0f);
    glEnd();

Здесь инициализация FBO и буфера рендеринга 3:

// frame buffer object
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);

// render buffer as color buffer
glGenRenderbuffers(1, &colorBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as color buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);

// render buffer as depth buffer
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as depth buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);

glGenRenderbuffers(1, &stencilBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as stencil buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_BUFFER, GL_RENDERBUFFER, stencilBuffer);

И, наконец, здесь 3 метода для передачи пикселей:

QImage FBO::getImage()
{
    // this is called Pixel Transfer operation: http://www.opengl.org/wiki/Pixel_Transfer
    uchar *pixels;
    pixels = new uchar[width * height * 4];
    for(int i=0; i < (width * height * 4) ; i++ ) {
        pixels[i] = 0;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glReadPixels( 0,0,  width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);
    qi = qi.rgbSwapped();

    return qi;
}

QImage FBO::getDepth()
{
    // this is called Pixel Transfer operation: http://www.opengl.org/wiki/Pixel_Transfer
    uchar *pixels;
    pixels = new uchar[width * height * 4];
    for(int i=0; i < (width * height * 4) ; i++ ) {
        pixels[i] = 0;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
    glReadPixels( 0,0,  width, height, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);
    qi = qi.rgbSwapped();

    return qi;
}

QImage FBO::getStencil()
{
    // this is called Pixel Transfer operation: http://www.opengl.org/wiki/Pixel_Transfer
    uchar *pixels;
    pixels = new uchar[width * height * 4];
    for(int i=0; i < (width * height * 4) ; i++ ) {
        pixels[i] = 0;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
    glReadPixels( 0,0,  width, height, GL_STENCIL_INDEX, GL_FLOAT, pixels);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);
    qi = qi.rgbSwapped();

    return qi;

}

Вот скриншот 2 (цвет и глубина, с трафаретом я получаю пустой QImage):

Цветной это именно то, что я рисую (перевернул, но я думаю, что это нормально). Глубина .. Я ожидаю белое изображение с градиентом серого треугольника .. Наверняка я делаю какую-то ошибку в формате изображения (GL_FLOAT?) но я пробовал некоторые комбинации, и это лучший результат ... фиолетовый фон с блестящими цветами внутри него ... и с трафаретным буфером ... я ожидаю контур белого треугольника на черном фоне, но .. понятия не имею, почему я ничего не вижу ..

РЕДАКТИРОВАТЬ:

Ладно, никогда не используйте только трафаретный буфер, поэтому я немного изменил рефакторинг.

при объявлении FBO:

// render buffer for both depth and stencil buffer
glGenRenderbuffers(1, &depthStencilBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as depth buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);

пиксельная передача глубины:

QImage FBO::getDepth()
{
    std::vector<uchar> pixels;
    pixels.reserve(width * height*4);
    for(int i=0; i < (width * height*4) ; i++ ) {
        pixels.push_back(0);
    }

    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
    glReadPixels( 0,0,  width, height,  GL_DEPTH24_STENCIL8, GL_UNSIGNED_BYTE, pixels.data());

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    std::vector<uchar> _pixels;
    _pixels.reserve(width * height*4);
    for(int i=0; i < (width * height*4) ; i++ ) {
        uchar p_red = pixels[i];
        uchar p_green = pixels[i+1];
        uchar p_blue = pixels[i+2];

        uchar p_stencil = pixels[i+3];

        _pixels.push_back(p_red);
        _pixels.push_back(p_green);
        _pixels.push_back(p_blue);

        _pixels.push_back(255); // alpha
    }

    QImage qi = QImage(_pixels.data(), width, height, QImage::Format_ARGB32);
    //qi = qi.rgbSwapped();

    return qi;
}

трафарет похож, но с использованиемp_stencil с компонентом RGB

.. В результате получается черное изображение как для глубины, так и для трафарета.

РЕДАКТИРОВАТЬ

благодаря ответу Николаса мне удалось использовать буфер визуализации как для буфера глубины, так и для буфера трафарета, и извлечь компонент глубины, чтобы он соответствовалQImage::Format_ARGB32 с этим кодом:

QImage FBO1::getDepth()
{
    // sizeof( GLuint ) = 4 byte
    // sizeof( uchar ) = 1 byte

    std::vector<GLuint> pixels(width * height);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
    glReadPixels( 0,0,  width, height,  GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, pixels.data());
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    std::vector<uchar> _pixels;
    for(int i=0; i < (width * height) ; i++ ) {
        GLuint color = pixels[i];

        float temp = (color & 0xFFFFFF00) >> 8; // 24 bit of depth component

        // remap temp that goes from 0 to 0xFFFFFF (24 bits) to
        // _temp that goes from 0 to 0xFF (8 bits)
        float _temp = (temp / 0xFFFFFF) * 0xFF;

        _pixels.push_back((uchar)_temp);
        _pixels.push_back((uchar)_temp);
        _pixels.push_back((uchar)_temp);
        _pixels.push_back(255);
    }

    QImage qi = QImage(_pixels.data(), width, height, QImage::Format_ARGB32);
    qi = qi.rgbSwapped();

    return qi;
}

.. Еще некоторые проблемы с компонентом трафарета (следующий код не работает: он производит глюки изображения):

QImage FBO1::getStencil()
{
    // sizeof( GLuint ) = 4 byte
    // sizeof( uchar ) = 1 byte

    std::vector<GLuint> pixels(width * height);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
    glReadPixels( 0,0,  width, height,  GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, pixels.data());
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    std::vector<uchar> _pixels;
    for(int i=0; i < (width * height); i++ ) {
        GLuint color = pixels[i];

        uchar temp = (color & 0x000000FF); // last 8 bit of depth component

        _pixels.push_back(temp);
        _pixels.push_back(temp);
        _pixels.push_back(temp);
        _pixels.push_back(255);
    }

    QImage qi = QImage(_pixels.data(), width, height, QImage::Format_ARGB32);
    qi = qi.rgbSwapped();

    return qi;
}

Ответы на вопрос(2)

Ваш ответ на вопрос