如何在QGraphicsItem :: paint()中将QGLFrameBufferObject绘制到painter上

Chr*_*phe 13 opengl qt

我的问题的小版本

在QGraphicsItem :: paint()函数中,我有一个QGLFrameBufferObject.如何在作为参数传递的画家的paintdevice上获得它?(假设QGraphicsItem位于由QGraphicsView呈现的场景中,该场景具有QGLWidget作为视口=> 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?
}
Run Code Online (Sandbox Code Playgroud)

我查看了Qt提供的framebufferobject和pbuffer示例.在那里使用自定义opengl代码在QGLWidget中绘制fbo/pbuffer.是否可以在QGraphicsItem的paint()方法中执行相同的操作并将场景/视图中的QGraphisItem的位置考虑在内?

我的问题的大版本

情况草图

我有一个QGraphicsScene.它是一个具有QGraphicsEffect的项目(通过覆盖QGraphicsEffect的draw()来实现自己的实现).场景由QGraphicsView呈现,其中QGLWidget作为视口.

在QGraphicsEffect :: draw(QPainter*)中,我必须生成一些pixmap,然后我想使用提供的画家绘制(画家将QGLWidget作为paintdevice).构建像素图是一些绘制调用的组合,我希望这些在硬件中完成.

简化示例:(我不会在我的draw()方法中调用sourcepixmap,因为不需要演示我的问题)

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);
}
Run Code Online (Sandbox Code Playgroud)

实际问题

我关心的是我的代码的最后一行:pbuffer-> toImage().我不想用这个.由于性能原因,我不想进行QImage转换.有没有办法从我的glpixelbuffer获取pixmap,然后使用painter-> drawpixmap()?

我知道我也可以使用以下方法将pbuffer复制到纹理:

GLuint dynamicTexture = pbuffer.generateDynamicTexture();
pbuffer.updateDynamicTexture(dynamicTexture);
Run Code Online (Sandbox Code Playgroud)

但我不知道如何将这种纹理带到"画家"身上.

Mis*_*sch 8

扩展leemes的答案,这是一个解决方案,它也可以处理多重采样帧缓冲对象.

首先,如果你想在QGLWidget上绘图,你可以简单地使用他的答案中建议的OpenGL命令leemes.请注意,有一个现成的drawTexture() 命令可用,它将此代码简化为以下内容:

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

要绘制多重采样FBO,您可以使用它们将它们转换为非多采样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());
Run Code Online (Sandbox Code Playgroud)

但是,据我所知,您无法在非OpenGL上下文中使用OpenGL命令进行绘制.为此,首先需要将帧缓冲区转换为(软件)图像,如使用QImage,fbo.toImage()并使用QPainter而不是fbo直接绘制.


lee*_*mes 5

我想我明白了.我QPainter::beginNativePainting()在paintEvent中使用混合OpenGL命令:

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();
}
Run Code Online (Sandbox Code Playgroud)

我希望这也适用于QGraphicsItem的paintEvent(QGraphicsView使用QGLWidget作为视口),因为我只是QGLWidget::paintEvent直接测试它.

但是,仍然存在以下问题:我不知道如何绘制多重采样帧缓冲区.文件QGLFramebufferObject::texture()说:

如果使用多重采样帧缓冲对象,则此函数返回的值将无效.