How to draw QGLFrameBufferObject onto the painter from within QGraphicsItem::paint()
在QGraphicsItem :: paint()函数中,我有一个QGLFrameBufferObject。如何在作为参数传递的painter的paintdevice上获取它? (前提是QGraphicsItem位于由QGraphicsView渲染的场景中,该场景具有QGLWidget作为视口=> painter使用的是opengl引擎)
1 2 3 4 5 6 7 8 9 | 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作为绘画设备)进行绘制。构造像素图是一些绘制调用的组合,我希望这些可以在硬件中完成。
简化的示例:(我没有在我的draw()方法中调用sourcepixmap,因为不需要它来演示我的问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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复制到纹理:
1 2 | GLuint dynamicTexture = pbuffer.generateDynamicTexture(); pbuffer.updateDynamicTexture(dynamicTexture); |
但我不知道如何将这种纹理粘贴到"画家"上。
扩展leemes的答案,这是一个还可以处理多样本帧缓冲对象的解决方案。
首先,如果要在QGLWidget上绘制,则只需使用OpenGL命令
莱姆斯在回答中建议。请注意,有一个现成的
命令可用,此代码简化为以下内容:
1 2 3 4 5 6 | void Widget::drawFBO(QPainter &painter, QGLFramebufferObject &fbo, QRect target) { painter.beginNativePainting(); drawTexture(target, fbo.texture()); painter.endNativePainting(); } |
要绘制多样本FBO,可以将其转换为非多样本FBO。
使用
/驱动程序组合支持此功能!):
1 2 3 4 5 6 7 8 9 10 | 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直接。
我想我知道了。我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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作为视口),因为我只是直接在
但是,仍然存在以下问题:我不知道如何绘制多样本帧缓冲区。
If a multisample framebuffer object is used then the value returned from this function will be invalid.