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. How to do (dynamic) offscreen render with QOffscreenSurface in Qt5 correctly?
Forum Updated to NodeBB v4.3 + New Features

How to do (dynamic) offscreen render with QOffscreenSurface in Qt5 correctly?

Scheduled Pinned Locked Moved Unsolved General and Desktop
2 Posts 2 Posters 2.3k Views
  • 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.
  • M Offline
    M Offline
    MartinChan 0
    wrote on last edited by
    #1

    I am try to do some offscreen rendering jobs in Qt5.3,and I want to use QOpenGLFramebufferObject::toImage to output each pictures(I want to output a few pictures when render() draws different things).Following the instructions of this ,I succeeded in offscreen rendering my first pic and outputing it. So to future on,I write an example as the following code and here is a package in Google.I can get the first fbo content(and its output file correctly ,but from the second time ,the fbo was not re-render() and it always output the same pictures).So I want to know what should I do after I finish one time offscreen render to make sure the next time would be correct in qt?Or is there anyone could tell me how to set animation correctly in QOffscreenSurface?

    qtestofffscreen.h:

    #ifndef QTESTOFFSCREEN_H
    #define QTESTOFFSCREEN_H
    
    #include <QOffscreenSurface>
    #include <QWindow>
    #include <QtGui/QOpenGLFunctions_3_3_Core>
    #include <QImage>
    #include <QGLFramebufferObject>
    #include <QOpenGLPaintDevice>
    #include <QOpenGLFunctions>
    #include <QMutex>
    #include <QMutexLocker>
    
    class QTestOffScreen : public QOffscreenSurface,
                       protected QOpenGLFunctions_3_3_Core
    {
        Q_OBJECT
    
    public:
    explicit QTestOffScreen(
            QScreen* targetScreen = nullptr,
            const QSize& size = QSize (1, 1));
    ~QTestOffScreen();
    
    virtual void render();
    virtual void initialize();
    void renderNow();
    void setAnimating(bool animating);
    
    bool event(QEvent *) override;
    
    void renderLater();
    int  counts;
    
    private:
    QGLFramebufferObject *fbo;
    bool m_animating;
    bool m_update_pending;
    
    QOpenGLContext *m_context;
    QOpenGLPaintDevice *m_device;
    
    QSize m_size;
    
    QMutex mutex;
    
    signals:
    void doneImg(int index);
    };
    
    #endif // QTESTOFFSCREEN_H
    

    qtestofffscreen.cpp:

    #include "qtestoffscreen.h"
    #include <QTime>
    #include <QDebug>
    #include <QCoreApplication>
    #include <QOpenGLFramebufferObject>
    
    QTestOffScreen::QTestOffScreen(QScreen *targetScreen,
                                   const QSize &size):
        QOffscreenSurface(targetScreen),
        m_size(size),
        fbo(Q_NULLPTR),
        m_context(Q_NULLPTR),
        m_device(Q_NULLPTR),
        counts(100)
    {
        requestedFormat().setVersion(3,3);
        setFormat(requestedFormat());
        create();
    
        m_context = new QOpenGLContext(this);
        m_context->setFormat(format());
    
        if (m_context->create())
        {
            m_context->makeCurrent(this);
            m_context->functions()->initializeOpenGLFunctions();
        }else
        {
            delete m_context;
            m_context = Q_NULLPTR;
            throw ("Still wrong here");
        }
    
        //To make sure m_context was initialized
        //in first time entering renderNow()
        delete m_context;
        m_context = Q_NULLPTR;
    }
    
    QTestOffScreen::~QTestOffScreen()
    {
        delete m_context;
        delete m_device;
        if (fbo)
            delete fbo;
    }
    
    void QTestOffScreen::render()
    {
        glClearColor(0.0f,0.0f,0.0f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT
              | GL_DEPTH_BUFFER_BIT
              | GL_STENCIL_BUFFER_BIT
              | GL_TEXTURE_BIT);
    
        glViewport(0,0,1920,1080);
        glOrtho(0,1920,0,1080,0,1);
    
        glColor3f(1.0,0.0,0.0);
    
        float tmp = float(qrand()%1000);
        float count = (float)counts * 10.0f;
    
        glLineWidth(3.0f);
        glBegin(GL_LINE_LOOP);
            glVertex2f(count ,count );
            glVertex2f(count + 100,count);
            glVertex2f(count + 50,count + 100);
        glEnd();
    
        qDebug()<<QString("current tmp is %1").arg(count);
    
    }
    
    void QTestOffScreen::initialize()
    {
    
        if (!fbo)
        {
            fbo = new QGLFramebufferObject(1920,1080,GL_TEXTURE_2D);
        }
    
        fbo->bind();
    }
    
    void QTestOffScreen::renderNow()
    {
        bool needsInitialize = false;
        if (!m_context)
        {
            m_context = new QOpenGLContext(this);
            m_context->setFormat(requestedFormat());
            m_context->create();
    
            if (m_context->isValid())
            {
                qDebug()<<"Right Here when creating m_context in renderNow";
            }
    
            needsInitialize = true;
        }
    
        if ( !m_context->makeCurrent(this) )
        {
            qDebug()<<"This fails in makeCurrent";
        }
    
        if (needsInitialize)
        {
            initializeOpenGLFunctions();
            initialize();
        }
    
            render();
    
            qDebug()<<counts;
            counts--;
            fbo->toImage().save(QString::number(counts) + QString(".png"));
    
    
        m_context->doneCurrent();
    
        if (counts >= 0)
        {
            m_update_pending = false;
            emit doneImg(counts);
        }
    }
    
    void QTestOffScreen::setAnimating(bool animating)
    {
        m_animating = animating;
    
        m_update_pending = false;
    
        if (m_animating)
            renderLater();
    }
    
    bool QTestOffScreen::event(QEvent *event)
    {
        switch (event->type())
        {
        case QEvent::UpdateRequest:
            m_update_pending = true;
            renderNow();
            return true;
        default:
            return QOffscreenSurface::event(event);
        }
    }
    
    void QTestOffScreen::renderLater()
    {
        if (!m_update_pending)
        {
            m_update_pending = true;
            QCoreApplication::postEvent(this,new QEvent(QEvent::UpdateRequest));
        }
    }
    
    void QTestOffScreen::generateImg(QImage *tmp_img_pointer)
    {
        GLint viewPort[4]={0};
        glGetIntegerv(GL_VIEWPORT,viewPort);
    
        int win_width,win_height;
        win_width = 1920;
        win_height = 1080;
    
        GLubyte *colorArr=new GLubyte[win_width*win_height*3];
    
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glReadBuffer (GL_FRONT);
    
        int tmp_x,tmp_y;
        tmp_x = 0;
        tmp_y = 0;
    
        glReadPixels(tmp_x,tmp_y,win_width,win_height,
                     GL_RGB,GL_UNSIGNED_BYTE,colorArr);
    
        int winrows = tmp_img_pointer->height();
        int wincols = tmp_img_pointer->width ();
    
    
        for(int ii=0; ii < winrows * wincols * 3; ii ++)
        {
            if((colorArr[ii] <0)|(colorArr[ii] >255))
            { colorArr[ii] = 255; }
        }
    
    
        for(int j=0;j<winrows;j++)
            for(int i=0;i<wincols;i++)
            {
                int index=(j*wincols+i)*3;
                QRgb value=qRgb(colorArr[index+2],
                                colorArr[index+1],
                                colorArr[index  ]);
                tmp_img_pointer->setPixel(i,winrows-j-1,value);
            }
        delete colorArr;
    }
    

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "qtestoffscreen.h"
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    
        QTestOffScreen *scr;
    
    private slots:
        void ReceiveCurrentIndex(int);
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        QSurfaceFormat format;
        format.setSamples(1);
        format.setRenderableType(QSurfaceFormat::OpenGL);
    
        scr = new QTestOffScreen();
    
        connect(scr,SIGNAL(doneImg(int)),this,SLOT(ReceiveCurrentIndex(int)));
    
        scr->setFormat(format);
    
        scr->setAnimating(true);//Start rendering animation here.
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::ReceiveCurrentIndex(int)
    {
        Sleep(100);
    
        scr->renderLater();
    }
    
    m.sueM 1 Reply Last reply
    0
    • M MartinChan 0

      I am try to do some offscreen rendering jobs in Qt5.3,and I want to use QOpenGLFramebufferObject::toImage to output each pictures(I want to output a few pictures when render() draws different things).Following the instructions of this ,I succeeded in offscreen rendering my first pic and outputing it. So to future on,I write an example as the following code and here is a package in Google.I can get the first fbo content(and its output file correctly ,but from the second time ,the fbo was not re-render() and it always output the same pictures).So I want to know what should I do after I finish one time offscreen render to make sure the next time would be correct in qt?Or is there anyone could tell me how to set animation correctly in QOffscreenSurface?

      qtestofffscreen.h:

      #ifndef QTESTOFFSCREEN_H
      #define QTESTOFFSCREEN_H
      
      #include <QOffscreenSurface>
      #include <QWindow>
      #include <QtGui/QOpenGLFunctions_3_3_Core>
      #include <QImage>
      #include <QGLFramebufferObject>
      #include <QOpenGLPaintDevice>
      #include <QOpenGLFunctions>
      #include <QMutex>
      #include <QMutexLocker>
      
      class QTestOffScreen : public QOffscreenSurface,
                         protected QOpenGLFunctions_3_3_Core
      {
          Q_OBJECT
      
      public:
      explicit QTestOffScreen(
              QScreen* targetScreen = nullptr,
              const QSize& size = QSize (1, 1));
      ~QTestOffScreen();
      
      virtual void render();
      virtual void initialize();
      void renderNow();
      void setAnimating(bool animating);
      
      bool event(QEvent *) override;
      
      void renderLater();
      int  counts;
      
      private:
      QGLFramebufferObject *fbo;
      bool m_animating;
      bool m_update_pending;
      
      QOpenGLContext *m_context;
      QOpenGLPaintDevice *m_device;
      
      QSize m_size;
      
      QMutex mutex;
      
      signals:
      void doneImg(int index);
      };
      
      #endif // QTESTOFFSCREEN_H
      

      qtestofffscreen.cpp:

      #include "qtestoffscreen.h"
      #include <QTime>
      #include <QDebug>
      #include <QCoreApplication>
      #include <QOpenGLFramebufferObject>
      
      QTestOffScreen::QTestOffScreen(QScreen *targetScreen,
                                     const QSize &size):
          QOffscreenSurface(targetScreen),
          m_size(size),
          fbo(Q_NULLPTR),
          m_context(Q_NULLPTR),
          m_device(Q_NULLPTR),
          counts(100)
      {
          requestedFormat().setVersion(3,3);
          setFormat(requestedFormat());
          create();
      
          m_context = new QOpenGLContext(this);
          m_context->setFormat(format());
      
          if (m_context->create())
          {
              m_context->makeCurrent(this);
              m_context->functions()->initializeOpenGLFunctions();
          }else
          {
              delete m_context;
              m_context = Q_NULLPTR;
              throw ("Still wrong here");
          }
      
          //To make sure m_context was initialized
          //in first time entering renderNow()
          delete m_context;
          m_context = Q_NULLPTR;
      }
      
      QTestOffScreen::~QTestOffScreen()
      {
          delete m_context;
          delete m_device;
          if (fbo)
              delete fbo;
      }
      
      void QTestOffScreen::render()
      {
          glClearColor(0.0f,0.0f,0.0f,1.0f);
          glClear(GL_COLOR_BUFFER_BIT
                | GL_DEPTH_BUFFER_BIT
                | GL_STENCIL_BUFFER_BIT
                | GL_TEXTURE_BIT);
      
          glViewport(0,0,1920,1080);
          glOrtho(0,1920,0,1080,0,1);
      
          glColor3f(1.0,0.0,0.0);
      
          float tmp = float(qrand()%1000);
          float count = (float)counts * 10.0f;
      
          glLineWidth(3.0f);
          glBegin(GL_LINE_LOOP);
              glVertex2f(count ,count );
              glVertex2f(count + 100,count);
              glVertex2f(count + 50,count + 100);
          glEnd();
      
          qDebug()<<QString("current tmp is %1").arg(count);
      
      }
      
      void QTestOffScreen::initialize()
      {
      
          if (!fbo)
          {
              fbo = new QGLFramebufferObject(1920,1080,GL_TEXTURE_2D);
          }
      
          fbo->bind();
      }
      
      void QTestOffScreen::renderNow()
      {
          bool needsInitialize = false;
          if (!m_context)
          {
              m_context = new QOpenGLContext(this);
              m_context->setFormat(requestedFormat());
              m_context->create();
      
              if (m_context->isValid())
              {
                  qDebug()<<"Right Here when creating m_context in renderNow";
              }
      
              needsInitialize = true;
          }
      
          if ( !m_context->makeCurrent(this) )
          {
              qDebug()<<"This fails in makeCurrent";
          }
      
          if (needsInitialize)
          {
              initializeOpenGLFunctions();
              initialize();
          }
      
              render();
      
              qDebug()<<counts;
              counts--;
              fbo->toImage().save(QString::number(counts) + QString(".png"));
      
      
          m_context->doneCurrent();
      
          if (counts >= 0)
          {
              m_update_pending = false;
              emit doneImg(counts);
          }
      }
      
      void QTestOffScreen::setAnimating(bool animating)
      {
          m_animating = animating;
      
          m_update_pending = false;
      
          if (m_animating)
              renderLater();
      }
      
      bool QTestOffScreen::event(QEvent *event)
      {
          switch (event->type())
          {
          case QEvent::UpdateRequest:
              m_update_pending = true;
              renderNow();
              return true;
          default:
              return QOffscreenSurface::event(event);
          }
      }
      
      void QTestOffScreen::renderLater()
      {
          if (!m_update_pending)
          {
              m_update_pending = true;
              QCoreApplication::postEvent(this,new QEvent(QEvent::UpdateRequest));
          }
      }
      
      void QTestOffScreen::generateImg(QImage *tmp_img_pointer)
      {
          GLint viewPort[4]={0};
          glGetIntegerv(GL_VIEWPORT,viewPort);
      
          int win_width,win_height;
          win_width = 1920;
          win_height = 1080;
      
          GLubyte *colorArr=new GLubyte[win_width*win_height*3];
      
          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
          glReadBuffer (GL_FRONT);
      
          int tmp_x,tmp_y;
          tmp_x = 0;
          tmp_y = 0;
      
          glReadPixels(tmp_x,tmp_y,win_width,win_height,
                       GL_RGB,GL_UNSIGNED_BYTE,colorArr);
      
          int winrows = tmp_img_pointer->height();
          int wincols = tmp_img_pointer->width ();
      
      
          for(int ii=0; ii < winrows * wincols * 3; ii ++)
          {
              if((colorArr[ii] <0)|(colorArr[ii] >255))
              { colorArr[ii] = 255; }
          }
      
      
          for(int j=0;j<winrows;j++)
              for(int i=0;i<wincols;i++)
              {
                  int index=(j*wincols+i)*3;
                  QRgb value=qRgb(colorArr[index+2],
                                  colorArr[index+1],
                                  colorArr[index  ]);
                  tmp_img_pointer->setPixel(i,winrows-j-1,value);
              }
          delete colorArr;
      }
      

      mainwindow.h:

      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      
      #include <QMainWindow>
      #include "qtestoffscreen.h"
      namespace Ui {
      class MainWindow;
      }
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          explicit MainWindow(QWidget *parent = 0);
          ~MainWindow();
      
      private:
          Ui::MainWindow *ui;
      
          QTestOffScreen *scr;
      
      private slots:
          void ReceiveCurrentIndex(int);
      };
      
      #endif // MAINWINDOW_H
      

      mainwindow.cpp:

      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      #include <QDebug>
      
      MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
      
          QSurfaceFormat format;
          format.setSamples(1);
          format.setRenderableType(QSurfaceFormat::OpenGL);
      
          scr = new QTestOffScreen();
      
          connect(scr,SIGNAL(doneImg(int)),this,SLOT(ReceiveCurrentIndex(int)));
      
          scr->setFormat(format);
      
          scr->setAnimating(true);//Start rendering animation here.
      
      }
      
      MainWindow::~MainWindow()
      {
          delete ui;
      }
      
      void MainWindow::ReceiveCurrentIndex(int)
      {
          Sleep(100);
      
          scr->renderLater();
      }
      
      m.sueM Offline
      m.sueM Offline
      m.sue
      wrote on last edited by
      #2

      Hi @MartinChan-0

      There is a thread "Qt3D Rendering offscreen" in the Qt Interest mailing list about it, starting on 2017, August 11th. Maybe you get some idea.

      -Michael.

      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