Подтвердить что ты не робот

Как нарисовать QGLFrameBufferObject на художника из QGraphicsItem:: paint()

Небольшая версия моего вопроса

В функции QGraphicsItem:: paint() у меня есть объект QGLFrameBufferObject. Как я могу получить его на рисовалом художника, который передается в качестве аргумента? (при условии, что QGraphicsItem находится в сцене, которая визуализируется QGraphicsView, у которой есть QGLWidget, поскольку viewport = > художник использует механизм opengl)

QGraphicsItem::paint(QPainter* painter, ...)
{
    QGLFramebufferObject fbo;
    QPainter p(fbo);
    ... // Some painting code on the fbo
    p.end();

    // What now? How to get the fbo content drawn on the painter?
}

Я рассмотрел примеры framebufferobject и pbuffer, снабженные Qt. Там fbo/pbuffer рисуется в QGLWidget, используя пользовательский код opengl. Можно ли сделать одно и то же в методе paint() объекта QGraphicsItem и занять позицию QGraphisItem в сцене/представлении?

Большая версия моего вопроса

Ситуационный эскиз

У меня есть QGraphicsScene. В нем есть элемент, который имеет QGraphicsEffect (собственная реализация путем переопределения draw() из QGraphicsEffect). Сцена визуализируется QGraphicsView, который имеет QGLWidget как область просмотра.

В QGraphicsEffect:: draw (QPainter *) мне нужно создать некоторую pixmap, которую я тогда хочу рисовать, используя предоставленный художник (у живописца есть QGLWidget как paintdevice). Построение pixmap - это комбинация некоторых вызовов рисования, и я хочу, чтобы они выполнялись в аппаратном обеспечении.

Упрощенный пример: (я не называю sourcepixmap в методе draw(), поскольку это не обязательно для демонстрации моей проблемы)

class OwnGraphicsEffect: public QGraphicsEffect
{
     virtual void draw(QPainter* painter);
}

void OwnGraphicsEffect::draw(QPainter* painter)
{
    QRect rect(0,0,100,100);
    QGLPixelBuffer pbuffer(rect.size(), QGLFormat(QGL::Rgba));
    QPainter p(pbuffer);
    p.fillRect(rect, Qt::transparent);
    p.end();

    painter->drawImage(QPoint(0,0), pbuffer->toImage(),rect);
}

Актуальная проблема

Мои проблемы связаны с последней строкой моего кода: pbuffer- > toImage(). Я не хочу это использовать. Из-за соображений производительности я не хочу преобразовывать QImage. Есть ли способ получить pixmap из моего glpixelbuffer, а затем использовать painter- > drawpixmap()?

Я знаю, что я также могу скопировать pbuffer в текстуру, используя:

GLuint dynamicTexture = pbuffer.generateDynamicTexture();
pbuffer.updateDynamicTexture(dynamicTexture);

но я понятия не имею, как получить эту текстуру на "художнике".

4b9b3361

Ответ 1

Расширение ответа на leemes, вот решение, которое также может обрабатывать многозадачные объекты фреймбуфера.

Во-первых, если вы хотите нарисовать QGLWidget, вы можете просто использовать команды OpenGL leemes предложил в своем ответе. Обратите внимание, что есть готовый к использованию drawTexture() доступная команда, которая упрощает этот код до следующего:

void Widget::drawFBO(QPainter &painter, QGLFramebufferObject &fbo, QRect target)
{
    painter.beginNativePainting();
    drawTexture(target, fbo.texture());
    painter.endNativePainting();
}

Чтобы рисовать мультисэмплы, вы можете преобразовать их в не мультисэмплы используя QGLFramebufferObject::blitFramebuffer (обратите внимание, что не все аппаратные средства /driver поддерживает эту функцию!):

if(fbo.format().samples() > 1)
{
    QGLFramebufferObject texture(fbo.size()); // the non-multisampled fbo
    QGLFramebufferObject::blitFramebuffer(
            &texture, QRect(0, 0, fbo.width(), fbo.height()),
            &fbo, QRect(0, 0, fbo.width(), fbo.height()));
    drawTexture(targetRect, texture.texture());
}
else
    drawTexture(targetRect, fbo.texture());

Однако, насколько я знаю, вы не можете рисовать с помощью команд OpenGL в контексте, отличном от OpenGL. Для этого вам сначала нужно преобразовать фреймбуфер в (программное) изображение, например QImage с использованием fbo.toImage() и нарисуйте это с помощью QPainter вместо fbo напрямую.

Ответ 2

Думаю, я понял это. Я использую QPainter::beginNativePainting() для смешивания команд OpenGL в paintEvent:

void Widget::drawFBO(QPainter &painter, QGLFramebufferObject &fbo, QRect target)
{
    painter.beginNativePainting();

    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glBindTexture(GL_TEXTURE_2D, fbo.texture());
    glBegin(GL_QUADS);
    glTexCoord2d(0.0,1.0); glVertex2d(target.left(),      target.top());
    glTexCoord2d(1.0,1.0); glVertex2d(target.right() + 1, target.top());
    glTexCoord2d(1.0,0.0); glVertex2d(target.right() + 1, target.bottom() + 1);
    glTexCoord2d(0.0,0.0); glVertex2d(target.left(),      target.bottom() + 1);
    glEnd();

    painter.endNativePainting();
}

Я надеюсь, что это также будет работать в paintEvent QGraphicsItem (где QGraphicsView использует QGLWidget как область просмотра), так как я тестировал его непосредственно в QGLWidget::paintEvent.

Однако есть еще одна проблема: я не знаю, как рисовать многозадачный фреймбуфер. В документации QGLFramebufferObject::texture() говорится:

Если используется многозадачный объект фреймбуфера, значение, возвращаемое из этой функции, будет недопустимым.