Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QPainter effects removed when rendering a QOpenGLWidget into a QPixmap
Forum Updated to NodeBB v4.3 + New Features

QPainter effects removed when rendering a QOpenGLWidget into a QPixmap

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 3 Posters 749 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    hexo
    wrote on last edited by hexo
    #1

    I have a QOpenGLWidget that does some OpenGL rendering and some non-OpenGL rendering using a QPainter. The widget looks OK but when I try to create a screenshot of the widget by rendering it into a QPixmap, suddenly all effects that are painted using QPainter disappear. Here is a minimal code sample to reproduce the issue:

    #include <QApplication>
    #include <qopenglwidget.h>
    #include <qopenglfunctions.h>
    #include <qpushbutton.h>
    #include <QPainter>
    
    class MainWidget : public QOpenGLWidget, QOpenGLFunctions{
    public:
    
        QPushButton* screenshot_button;
    
        MainWidget(QWidget* parent=nullptr) : QOpenGLWidget(parent){
            screenshot_button = new QPushButton("sreenshot", this);
            QObject::connect(screenshot_button, &QPushButton::clicked, [this](){
                take_screenshot();
            });
        }
    
        void initializeGL(){
            initializeOpenGLFunctions();
        }
    
        void take_screenshot(){
            QPixmap pixmap(size());
            render(&pixmap, QPoint(), QRegion(rect()));
            pixmap.save("screenshot.png");
        }
    
        void paintGL(){
            QPainter painter(this);
    
            painter.beginNativePainting();
            glClearColor(0.80, 0.80, 0.80, 1);
            glClear(GL_COLOR_BUFFER_BIT);
            painter.endNativePainting();
    
            // this disappears when the screenshot button is pressed!
            // also it is not present in the screenshot
            painter.drawRect(QRect(0, 0, 100, 100));
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWidget w;
        w.show();
        return a.exec();
    }
    
    

    Before pressing the button the widget looks normal:
    screenshot1.png

    But after pressing the screenshot button, the rectangle disappears from the widget (also it is absent from screenshot.png) until I resize the window which forces a re-render.
    screenshot.png

    I am using qt 6.5 on windows 10.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What do you get if using grabFramebuffer ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • H Offline
        H Offline
        hexo
        wrote on last edited by
        #3

        When I replace the contents of take_screenshot with this:

                QImage img = grabFramebuffer();
                QPixmap pixmap = QPixmap::fromImage(img);
                pixmap.save("screenshot.png");
        

        Here is the resulting screenshot:
        screenshot.png

        Now it has the rectangle but it still is not what I want because it doesn't render the rest of the widgets.

        H 1 Reply Last reply
        0
        • H hexo

          When I replace the contents of take_screenshot with this:

                  QImage img = grabFramebuffer();
                  QPixmap pixmap = QPixmap::fromImage(img);
                  pixmap.save("screenshot.png");
          

          Here is the resulting screenshot:
          screenshot.png

          Now it has the rectangle but it still is not what I want because it doesn't render the rest of the widgets.

          H Offline
          H Offline
          hexo
          wrote on last edited by
          #4

          Should I report this as a bug or is this intended behavior?

          SGaistS 1 Reply Last reply
          0
          • H hexo

            Should I report this as a bug or is this intended behavior?

            SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            I think that it would rather be a feature request.

            One possible workaround (I haven't tried it though) would be to grab the framebuffer and then apply the painting on the returned image. Not ideal but could be enough for your needs.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            H 1 Reply Last reply
            1
            • SGaistS SGaist

              I think that it would rather be a feature request.

              One possible workaround (I haven't tried it though) would be to grab the framebuffer and then apply the painting on the returned image. Not ideal but could be enough for your needs.

              H Offline
              H Offline
              hexo
              wrote on last edited by
              #6

              @SGaist Thanks, while this might work for the simple minimal code that I provided, the actual use case is in a complex application with many widgets drawn on top of the QOpenGLWidget. So simply drawing on the pixmap writes on the other widgets drawn on top of the QOpenGLWiddget.

              Also I don't know if it is a feature request. What feature exactly am I requesting XD? I just want render to work correctly when rendering into a pixmap.

              1 Reply Last reply
              0
              • C Offline
                C Offline
                CPPUIX
                wrote on last edited by
                #7

                Repost

                Solution 1:

                From QScreen::grabWindow() documentation:

                The grabWindow() function grabs pixels from the screen, not from the window, i.e. if there is another window partially or entirely over the one you grab, you get pixels from the overlying window, too.

                Meaning it grabs from the framebuffer unlike QWidget::grab and QWidget::render which ask the widget to render itself.

                So it could be used instead of render() to avoid the problems caused by combining the latter with OpenGL:

                void take_screenshot()
                {
                    QGuiApplication::primaryScreen()->grabWindow(winId()).save("screenScreenshot.png");
                }
                

                Solution 2:

                Less straightforward but just in case render is a must.

                Use a bool to disable openGL when calling render in take_screenshot(), and make sure you call grabFramebuffer() before.

                void take_screenshot()
                {
                    grabFramebuffer();
                
                    QPixmap pixmap(size());
                
                    enable_opengl=false;
                    render(&pixmap, QPoint(), QRegion(rect()));
                    enable_opengl=true;
                
                    pixmap.save("renderScreenshot.png");
                }
                
                void paintGL()
                {
                    QPainter painter(this);
                
                    if(enable_opengl)
                    {
                        glClearColor(0.80, 0.80, 0.80, 1);
                        glClear(GL_COLOR_BUFFER_BIT);
                    }
                
                    painter.fillRect(QRect(10, 10, 100, 100), Qt::green);
                }
                
                1 Reply Last reply
                0
                • C Offline
                  C Offline
                  CPPUIX
                  wrote on last edited by
                  #8

                  If possible, I'm hoping to get an explanation about the 2nd solution, because I stumbled upon it while experimenting.

                  I have never used OpenGL, but I'm interested in why calling grabFrameBuffer() and disabling OpenGL before calling render fixes the problem (I'm not even sure it does fix it)?

                  I read that grabFrameBuffer() relies on glReadPixels(), and read its documentation, but it's still unclear to me.

                  I also took a look at grabFrameBuffer source code to try and see if I can replicate what it's doing without calling it, but failed to understand that as well.

                  I'm just trying to learn something new, so it's not a problem I'm facing or an urgency.

                  Thanks if anyone decides to look into this!

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved