如何从 QGraphicsItem::paint() 中将 QGLFrameBufferObject 绘制到画家上

发布于 2024-12-01 05:32:37 字数 1724 浏览 0 评论 0原文

我的问题的小版本

在 QGraphicsItem::paint() 函数中我有一个 QGLFrameBufferObject。如何在作为参数传递的画家的绘画设备上获取它? (假设 QGraphicsItem 位于由 QGraphicsView 渲染的场景中,该场景具有 QGLWidget 作为视口 => 画家正在使用 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 示例。在那里,fbo/pbuffer 是使用自定义 opengl 代码在 QGLWidget 中绘制的。是否可以在 QGraphicsItem 的 Paint() 方法中执行相同的操作,并考虑 QGraphisItem 在场景/视图中的位置?

我的问题的大版本

情况草图

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

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

简化的示例:(我不在我的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);

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

Small version of my question

In a QGraphicsItem::paint() function I have a QGLFrameBufferObject. How do I get it on the paintdevice of the painter that is passed as an argument? (provided that the QGraphicsItem is in a scene that is being rendered by a QGraphicsView that has a QGLWidget as viewport => painter is using opengl engine)

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?
}

I have looked at the framebufferobject and pbuffer examples provided with Qt. There the fbo/pbuffer is drawn in a QGLWidget using custom opengl code. Is it possible to do the same thing within a paint() method of a QGraphicsItem and take the position of the QGraphisItem in the scene/view into account?

Big version of my question

Situation sketch

I have a QGraphicsScene. In it is an item that has a QGraphicsEffect (own implementation by overriding draw() from QGraphicsEffect). The scene is rendered by a QGraphicsView that has a QGLWidget as viewport.

In the QGraphicsEffect::draw(QPainter*) I have to generate some pixmap which I then want to draw using the painter provided (the painter has the QGLWidget as paintdevice). Constructing the pixmap is a combination of some draw calls and I want these to be done in hardware.

Simplified example: (I don't call sourcepixmap in my draw() method as it is not needed to demonstrate my problem)

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);
}

Actual problem

My concerns are with the last line of my code: pbuffer->toImage(). I don't want to use this. I don't want to have a QImage conversion because of performance reasons. Is there a way to get a pixmap from my glpixelbuffer and then use painter->drawpixmap()?

I know I also can copy the pbuffer to a texture by using :

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

but I have no idea on how to get this texture onto the "painter".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你的他你的她 2024-12-08 05:32:37

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

首先,如果你想在QGLWidget上绘图,你可以简单地使用OpenGL命令
莱姆斯在回答中建议。请注意,有一个随时可用的 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。

Extending leemes' answer, here is a solution which can also handle multisample framebuffer objects.

First, if you want to draw on a QGLWidget, you can simply use the OpenGL commands
leemes suggested in his answer. Note that there is a ready-to-use drawTexture()
command available, which simplifies this code to the following:

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

To draw multisample FBOs, you can convert them into non-multisample ones
using QGLFramebufferObject::blitFramebuffer (Note that not every hardware
/ driver combination supports this feature!):

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());

However, as far as I know, you can't draw using OpenGL commands on a non-OpenGL context.
For this, you first need to convert the framebuffer to a (software) image, like
a QImage using fbo.toImage() and draw this using your QPainter instead of the
fbo directly.

哭泣的笑容 2024-12-08 05:32:37

我想我明白了。我使用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() 的文档说:

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

I think I figured it out. I use the QPainter::beginNativePainting() to mix OpenGL commands in a 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();
}

I hope this will also work in the paintEvent of a QGraphicsItem (where the QGraphicsView uses a QGLWidget as the viewport), since I only tested it in QGLWidget::paintEvent directly.

There is, however, still the following problem: I don't know how to paint a multisample framebuffer. The documentation of QGLFramebufferObject::texture() says:

If a multisample framebuffer object is used then the value returned from this function will be invalid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文