【问题标题】:How to draw QGLFrameBufferObject onto the painter from within QGraphicsItem::paint()如何从 QGraphicsItem::paint() 中将 QGLFrameBufferObject 绘制到画家上
【发布时间】:2011-11-02 22:32:36
【问题描述】:

我的问题的小版本

在 QGraphicsItem::paint() 函数中,我有一个 QGLFrameBufferObject。如何在作为参数传递的画家的paintdevice上获取它? (前提是 QGraphicsItem 位于由具有 QGLWidget 作为视口的 QGraphicsView 渲染的场景中 => 画家正在使用 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?
}

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

我的问题的大版本

情景草图

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

在 QGraphicsEffect::draw(QPainter*) 中,我必须生成一些像素图,然后我想使用提供的画家进行绘制(画家将 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);
}

实际问题

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

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

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

但我不知道如何将此纹理添加到“画家”上。

【问题讨论】:

  • 我这里也有同样的问题。我不认为 QPainter 可以绘制 OpenGL 纹理,因为 QPainter 抽象了绘制设备以进行绘制,而不必使用 OpenGL。因此,我不认为有一个纯粹的基于 QPainter 的解决方案不需要将图像数据从显卡复制到您的进程(软件)中。我也不认为(但我不太确定)转换为 QPixmap 可以直接解决这个问题。但也许我错了?因此赏金。 :)

标签: qt opengl


【解决方案1】:

扩展 leemes 的回答,这是一个也可以处理多样本帧缓冲区对象的解决方案。

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

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

要绘制多样本 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());

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

【讨论】:

    【解决方案2】:

    我想我明白了。我使用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();
    }
    

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-25
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      相关资源
      最近更新 更多