Как нарисовать QGLFrameBufferObject на рисовальщике из QGraphicsItem :: paint () - PullRequest
13 голосов
/ 24 августа 2011

Маленькая версия моего вопроса

В функции QGraphicsItem :: paint () у меня есть QGLFrameBufferObject.Как я могу получить это на устройстве рисования художника, который передается в качестве аргумента?(при условии, что QGraphicsItem находится в сцене, которая визуализируется QGraphicsView, который имеет QGLWidget в качестве viewport => painter использует движок 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?
}

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

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

Ситуацияsketch

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

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

Упрощенный пример: (я не вызываю 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 из-за соображений производительности.Есть ли способ получить растровое изображение из моего glpixelbuffer и затем использовать painter-> drawpixmap ()?

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

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

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

Ответы [ 2 ]

7 голосов
/ 23 июля 2012

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

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

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

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

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 на не-Открытый контекст.Для этого вам сначала нужно преобразовать кадровый буфер в (программный) образ, например, QImage, используя fbo.toImage(), и нарисовать его, используя свой QPainter вместо fbo напрямую.

5 голосов
/ 23 июля 2012

Думаю, я понял это.Я использую 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() гласит:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...