Как нарисовать 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);
но я понятия не имею, как получить эту текстуру на "художнике".
Ответы
Ответ 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()
говорится:
Если используется многозадачный объект фреймбуфера, значение, возвращаемое из этой функции, будет недопустимым.