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



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


  • 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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.