Details
-
Suggestion
-
Resolution: Done
-
P2: Important
-
5.4.2, 5.9
-
None
-
Windows 7 x64, Qt 5.4.2 x64, Nvidia Quadro K3100M, recent drivers
-
2ea90c56f2924acc5c620ed7c29a48c72a42efd3
Description
I have a hidden QOpenGLWidget I want to capture. This is only possible by doing something along those lines:
void GLWidget::drawOffscreen() { //the context should be valid. make sure it is current for painting makeCurrent(); if (!m_isInitialized) { initializeGL(); resizeGL(width(), height()); } if (!m_fbo || m_fbo->width() != width() || m_fbo->height() != height()) { //allocate additional? FBO for rendering or resize it if widget size changed delete m_fbo; QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); m_fbo = new QOpenGLFramebufferObject(width(), height(), format); resizeGL(width(), height()); } //#1 DOES NOT WORK: bind FBO and render() widget m_fbo->bind(); QOpenGLPaintDevice fboPaintDev(width(), height()); QPainter painter(&fboPaintDev); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); render(&painter); painter.end(); //You could now grab the content of the framebuffer we've rendered to QImage image1 = m_fbo->toImage(); image1.save(QString("fb1.png")); m_fbo->release(); //#1 -------------------------------------------------------------- //#2 WORKS: bind FBO and render stuff with paintGL() call m_fbo->bind(); paintGL(); //You could now grab the content of the framebuffer we've rendered to QImage image2 = m_fbo->toImage(); image2.save(QString("fb2.png")); m_fbo->release(); //#2 -------------------------------------------------------------- //bind default framebuffer again. not sure if this necessary and isn't supposed to use defaultFramebuffer()... m_fbo->bindDefault(); doneCurrent(); }
I had expected due to QOpenGLWidget being backed by a FBO the widget would render() just fine, even without an extra FBO.
Now, Additionally inside paintGL, when using QPainter to paint, this only works when the widget is visible. If the widget is hidden you have to provide a QOpenGLPaintDevice in paintGL():
void GLWidget::paintGL() { //When doing mixed QPainter/OpenGL rendering make sure to use a QOpenGLPaintDevice, otherwise only OpenGL content is visible! //I'm not sure why, because according to the docs (http://doc.qt.io/qt-5/topics-graphics.html) this is supposed to be the same... QOpenGLPaintDevice fboPaintDev(width(), height()); QPainter painter(&fboPaintDev); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); //This is what you'd use (and what would work) if the widget was visible //QPainter painter; //painter.begin(this); //now start OpenGL painting painter.beginNativePainting(); glClearColor(0.5f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ... painter.endNativePainting(); //draw non-OpenGL stuff with QPainter painter.drawText(20, 40, "Foo"); ... painter.end(); }
What is strange about this, is that when using a QGraphicsView with a QOpenGLWidget set as its viewport, the following code works, even with mixed OpenGL + non-OpenGL QGraphicsItems:
MainWindow::MainWindow() { scene = new QGraphicsScene; hiddenView = new QGraphicsView(scene); hiddenGLWidget = new QOpenGLWidget; hiddenView->setViewport(hiddenGLWidget); //hiddenView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); //hiddenView->show(); } void MainWindow::screenshot() { //DOES NOT WORK: try regular grab functions QPixmap pixmap1 = hiddenView->grab(); //image with scrollbars, no OpenGL content pixmap1.save("bla1.png"); QPixmap pixmap2 = hiddenGLWidget->grab(); //produces an empty image pixmap2.save("bla2.png"); //try grabbing only the QOpenGLWidget framebuffer QImage image1 = hiddenGLWidget->grabFramebuffer(); //null image image1.save("bla3.png"); //WORKS: render via FBO hiddenGLWidget->makeCurrent(); QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); QOpenGLFramebufferObject * fbo = new QOpenGLFramebufferObject(hiddenView->width(), hiddenView->height(), format); fbo->bind(); QOpenGLPaintDevice fboPaintDev(hiddenView->width(), hiddenView->height()); QPainter painter(&fboPaintDev); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); hiddenView->render(&painter); //WORKS and captures mixed OpenGL and non-OpenGL QGraphicsitems //hiddenView->repaint(); //does not work //hiddenView->scene()->render(&painter); //does not work //hiddenGLWidget->paintGL(); //might work. can not call, protected //hiddenGLWidget->render(&painter); //does not work //hiddenGLWidget->repaint(); //does not work painter.end(); QImage image2 = fbo->toImage(); image2.save("bla4.png"); fbo->release(); delete fbo; }
UPDATE with "MISSING INFO": I have roled my own class now, base on QWindow and createWindowContainer(), because QOpenGLWidget just wasn't working in my case. You can see how I did it at the end of this StackOverflow question. The new widget works fine when rendering while it's hidden.
Attachments
Issue Links
- relates to
-
QTBUG-61280 Hidden floating QOpenGLWidget produces a warning when calling render() on the MainWindow
-
- Closed
-
-
QTBUG-61295 grab() for QGraphicsView backed by QOpenGLWidget viewport
-
- Open
-