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. Do offscreen render(openGL) with Qt5
QtWS25 Last Chance

Do offscreen render(openGL) with Qt5

Scheduled Pinned Locked Moved General and Desktop
9 Posts 2 Posters 8.0k 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.
  • S Offline
    S Offline
    stereomatching
    wrote on 20 Jun 2013, 18:25 last edited by
    #1

    Using openGL to do some image processing, the first experiment is
    convert the color image to gray, everything are fine, but I don't want
    to show the widget.

    If I don't call "show()" the QGLWidget would not begin to render the texture
    Could I render the texture without showing the widget?
    Is QGLWidget a right tool to do that?

    part of the codes

    @
    #include <QDebug>

    #include "toGray.hpp"

    toGray::toGray(std::string const &vertex_file, std::string const &fragment_file, QWidget *parent)
    :basicGLWidget(vertex_file, fragment_file, parent) //read shaders, compile them, allocate VBO
    {
    }

    void toGray::initializeVertexBuffer()
    {
    std::vector<GLfloat> const vertex{
    -1.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 1.0f, 0.0f, 1.0f,
    -1.0f, -1.0f, 0.0f, 1.0f,
    1.0f, 1.0f, 0.0f, 1.0f,
    1.0f, -1.0f, 0.0f, 1.0f,
    -1.0f, -1.0f, 0.0f, 1.0f,
    };

    initializeVertexBufferImpl(vertex); //copy the data into QOpenGLBuffer
    
    QImage img(":/simpleGPGPU/images/emili.jpg");
    texture_addr_ = bindTexture(img);
    resize(img.width(), img.height());
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    

    }

    void toGray::paintGL()
    {
    qglClearColor(Qt::white);
    glClear(GL_COLOR_BUFFER_BIT);

    program_.bind();
    bind_buffer();
    program_.enableAttributeArray("qt_Vertex");
    program_.setAttributeBuffer( "qt_Vertex", GL_FLOAT, 0, 4);
    
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture_addr_);
    
    glDrawArrays(GL_TRIANGLES, 0, get_buffer(0).size());
    
    program_.disableAttributeArray("qt_Vertex");
    program_.release();
    glActiveTexture(0);
    release_buffer();
    

    }

    @

    vertex shader
    @
    attribute highp vec4 qt_Vertex;
    varying highp vec2 qt_TexCoord0;

    void main(void)
    {
    gl_Position = qt_Vertex;
    qt_TexCoord0 = (qt_Vertex.xy + vec2(1.0)) * 0.5;
    }

    @

    fragment shader
    @
    uniform sampler2D source;
    varying highp vec2 qt_TexCoord0;

    vec3 toGray(vec3 rgb)
    {
    return vec3(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114);
    }

    void main(void)
    {
    vec3 gray = toGray(texture2D(source, qt_TexCoord0).rgb);
    gl_FragColor = vec4(gray, 0.0);
    }
    @

    1 Reply Last reply
    0
    • 8 Offline
      8 Offline
      8majkel8
      wrote on 20 Jun 2013, 21:59 last edited by
      #2

      You have to work directly on OpenGL context.

      https://www.opengl.org/wiki/Creating_an_OpenGL_Context_(WGL)
      https://qt-project.org/doc/qt-4.8/qglcontext.html

      Do render frame you have to call "makeCurrent()":https://qt-project.org/doc/qt-4.8/qglcontext.html#makeCurrent at the beginning and "doneCurrent()":https://qt-project.org/doc/qt-4.8/qglcontext.html#doneCurrent in the end.

      Hope i'm right.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        stereomatching
        wrote on 21 Jun 2013, 02:55 last edited by
        #3

        Thanks, could you introduce me some examples?
        I want to process an image by openGL and save the image after process
        without showing the widget.

        For me, the threshold of openGL is pretty high, the rules are complicated

        1 Reply Last reply
        0
        • 8 Offline
          8 Offline
          8majkel8
          wrote on 21 Jun 2013, 11:16 last edited by
          #4

          Sorry that I could not give you straight example of that but there are many tutorials about rendering frame to texture on the web:

          http://lmgtfy.com/?q=opengl+render+to+texture

          One good and easy example:

          http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/

          To get texture pixels back from GPU to RAM (so that you can create QImage) you have to use "glReadPixels":https://www.opengl.org/sdk/docs/man/xhtml/glReadPixels.xml (read pixels from currently bound frame buffer) or "glGetTexImage":https://www.opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml (to read pixels from currently bound texture). Don't be surprised when obtained image is flipped upside down (you have to fix it manually ). Pixels might have mismatched channels, QImage does not support GL_RGBA (maybe combination of GL_RGB and QImage::Format_RGB888 could work).

          bq. For me, the threshold of openGL is pretty high, the rules are complicated

          Probably not. Only conversion from texture to QImage might course a little trouble. I strongly recommend you to use scanLine instead of setPixel.
          Rules are sometimes complicated yes, you sometimes cannot read pixels from GPU because you graphics card does not support given format (or do software processing instead).

          1 Reply Last reply
          0
          • S Offline
            S Offline
            stereomatching
            wrote on 22 Jun 2013, 09:02 last edited by
            #5

            Using QWindow to do some offscreen rendering, but the function
            "initializeOpenGLFunctions();" always make the program crash

            .hpp
            @
            #ifndef OFFSCREENEXP_HPP
            #define OFFSCREENEXP_HPP

            #include <QOpenGLFunctions>
            #include <QWindow>

            class QOpenGLContext;

            class offScreenExp : public QWindow, protected QOpenGLFunctions
            {
            public:
            explicit offScreenExp(QWindow *parent = 0);

            private:
            QOpenGLContext *context_;
            };

            #endif // OFFSCREENEXP_HPP

            @

            .cpp
            @
            #include <QOpenGLContext>

            #include <QDebug>

            #include "offScreenExp.hpp"

            offScreenExp::offScreenExp(QWindow *parent) :
            QWindow(parent),
            context_(nullptr)
            {
            setSurfaceType(QWindow::OpenGLSurface);

            if (!context_) {
                context_ = new QOpenGLContext(this);
                context_->setFormat(requestedFormat());
            
                if (!context_->create())
                    qFatal("Cannot create the requested OpenGL context!");
            
            
                qDebug()<<"create context";
            }
            
            context_->makeCurrent(this);
            
            qDebug()<<"initialize gl func";
            initializeOpenGLFunctions(); //crash at here
            qDebug()<<"after initialize gl func";
            

            }

            @

            1 Reply Last reply
            0
            • S Offline
              S Offline
              stereomatching
              wrote on 22 Jun 2013, 13:54 last edited by
              #6

              Looks like the problem is I haven't called "create()" in my codes
              Now the codes can compile, but the QImage return by the QOpenGLFrameBufferObject is empty.

              .hpp
              @
              #ifndef OFFSCREENEXP_HPP
              #define OFFSCREENEXP_HPP

              #include <QOpenGLFunctions>
              #include <QWindow>

              class QImage;
              class QOpenGLContext;

              class offScreenExp : public QWindow, protected QOpenGLFunctions
              {
              public:
              explicit offScreenExp(QWindow *parent = 0);

              QImage render();
              

              private:
              QOpenGLContext *context_;
              };

              #endif // OFFSCREENEXP_HPP

              @

              .cpp
              @
              #include <QImage>
              #include <QOpenGLBuffer>
              #include <QOpenGLContext>
              #include <QOpenGLFramebufferObject>
              #include <QOpenGLShaderProgram>
              #include <QString>
              #include <QWidget>

              #include <QDebug>

              #include "offScreenExp.hpp"

              offScreenExp::offScreenExp(QWindow *parent) :
              QWindow(parent),
              context_(nullptr)
              {
              setSurfaceType(QWindow::OpenGLSurface);
              setFormat(QSurfaceFormat());
              create();
              }

              QImage offScreenExp::render()
              {
              //create the context
              if (!context_) {
              context_ = new QOpenGLContext(this);
              QSurfaceFormat format;
              context_->setFormat(format);

                  if (!context_->create())
                      qFatal("Cannot create the requested OpenGL context!");
              }
              
              context_->makeCurrent(this);
              initializeOpenGLFunctions();
              
              //load image and create fbo
              QString const prefix("/Users/Qt/program/experiment_apps_and_libs/openGLTest/simpleGPGPU/");
              QImage img(prefix + "images/emili.jpg");
              if(img.isNull()){
                qFatal("image is null");
              }
              QOpenGLFramebufferObject fbo(img.size());
              qDebug()<<"bind success? : "<<fbo.bind();
              
              //if(glCheckFramebufferStatus(fbo.handle()) != GL_FRAMEBUFFER_COMPLETE){
              //    qDebug()<<"frame buffer error";
              //}
              qDebug()<<"has opengl fbo : "<<QOpenGLFramebufferObject::hasOpenGLFramebufferObjects();
              
              //use two triangles two cover whole screen
              std::vector<GLfloat> const vertex{
                  -1.0f,  1.0f, 0.0f, 1.0f,
                  1.0f,  1.0f, 0.0f, 1.0f,
                  -1.0f, -1.0f, 0.0f, 1.0f,
                  1.0f, 1.0f, 0.0f, 1.0f,
                  1.0f, -1.0f, 0.0f, 1.0f,
                  -1.0f, -1.0f, 0.0f, 1.0f,
              };
              
              //initialize vbo
              QOpenGLBuffer buffer(QOpenGLBuffer::VertexBuffer);
              buffer.create();
              buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
              buffer.bind();
              buffer.allocate(&vertex[0], vertex.size() * sizeof(GLfloat) );
              buffer.release();
              
              //create texture
              GLuint rendered_texture;
              glGenTextures(1, &rendered_texture);
              
              // "Bind" the newly created texture : all future texture functions will modify this texture
              glBindTexture(GL_TEXTURE_2D, rendered_texture);
              
              //naive solution, better encapsulate the format in a function
              if(img.format() == QImage::Format_Indexed8){
                  glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, img.width(), img.height(), 0, GL_RED, GL_UNSIGNED_BYTE, img.scanLine(0));
              }else if(img.format() == QImage::Format_RGB888){
                  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, img.scanLine(0));
              }else{
                  QImage temp = img.convertToFormat(QImage::Format_RGB888);
                  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, temp.scanLine(0));
              }
              
              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
              
              glBindTexture(GL_TEXTURE_2D, 0);
              
              //compile and link program
              QOpenGLShaderProgram program;
              if(!program.addShaderFromSourceCode(QOpenGLShader::Vertex,
                                                  "attribute highp vec4 qt_Vertex;"
                                                  "varying highp vec2 qt_TexCoord0;"
              
                                                  "void main(void)"
                                                  "{"
                                                  "   gl_Position =  qt_Vertex;"
                                                  "   qt_TexCoord0 = (qt_Vertex.xy + vec2(1.0)) * 0.5;"
                                                  "}")){
                  qDebug()<<"QOpenGLShader::Vertex error : " + program.log();
              }
              
              // Compile fragment shader
              if (!program.addShaderFromSourceCode(QOpenGLShader::Fragment,
                                                   "uniform sampler2D source;"
                                                   "varying highp vec2 qt_TexCoord0;"
              
                                                   "vec3 toGray(vec3 rgb)"
                                                   "{"
                                                   " return vec3(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114);"
                                                   "}"
              
                                                   "void main(void)"
                                                   "{"
                                                   "vec3 gray = toGray(texture2D(source, qt_TexCoord0).rgb);"
                                                   "gl_FragColor = vec4(gray, 0.0);"
                                                   "}"
                                                   )){
                  qDebug()<<"QOpenGLShader::Fragment error : " + program.log();
              }
              
              // Link shader pipeline
              if (!program.link()){
                  qDebug()<<"link error : " + program.log();
              }
              
              //render the texture as usual
              glClearColor(0, 0, 0, 1);
              glClear(GL_COLOR_BUFFER_BIT);
              glViewport(0, 0, img.width(), img.height());
              
              program.bind();
              buffer.bind();
              program.enableAttributeArray("qt_Vertex");
              program.setAttributeBuffer( "qt_Vertex", GL_FLOAT, 0, 4);
              
              glActiveTexture(GL_TEXTURE0);
              glBindTexture(GL_TEXTURE_2D, rendered_texture);
              
              glDrawArrays(GL_TRIANGLES, 0, buffer.size());
              
              program.disableAttributeArray("qt_Vertex");
              program.release();
              glActiveTexture(0);
              glBindTexture(GL_TEXTURE_2D, 0);
              buffer.release();
              
              return fbo.toImage();
              

              }

              @

              1 Reply Last reply
              0
              • 8 Offline
                8 Offline
                8majkel8
                wrote on 22 Jun 2013, 14:12 last edited by
                #7

                missing doneCurrent() call in render method ??

                67: buffer.release(); //you should probably remove this line

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  stereomatching
                  wrote on 22 Jun 2013, 14:39 last edited by
                  #8

                  remove line 67 and add doneCurrent at the end

                  @
                  glActiveTexture(0);
                  glBindTexture(GL_TEXTURE_2D, 0);
                  buffer.release();

                  context_->doneCurrent();
                  
                  return fbo.toImage();
                  

                  @

                  Still get a blank image

                  1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    stereomatching
                    wrote on 23 Jun 2013, 20:14 last edited by
                    #9

                    Edit the codes of offScreenExp::render part, begin from line 132
                    change the order of cleaning resource

                    @
                    glClearColor(0, 0, 0, 1);
                    glClear(GL_COLOR_BUFFER_BIT);
                    glViewport(0, 0, img.width(), img.height());

                    program.bind();
                    buffer.bind();
                    program.enableAttributeArray("qt_Vertex");
                    program.setAttributeBuffer( "qt_Vertex", GL_FLOAT, 0, 4);

                    glActiveTexture(GL_TEXTURE0);
                    glBindTexture(GL_TEXTURE_2D, rendered_texture);

                    //bind and create fbo
                    QOpenGLFramebufferObject fbo(img.size());
                    qDebug()<<"bind success? : "<<fbo.bind();

                    glDrawArrays(GL_TRIANGLES, 0, buffer.size());
                    QImage result = fbo.toImage();

                    program.disableAttributeArray("qt_Vertex");
                    program.release();
                    buffer.release();

                    fbo.release();
                    glActiveTexture(0);
                    glBindTexture(GL_TEXTURE_2D, 0);
                    context_->doneCurrent();

                    return result;
                    @

                    But I am still get a blank image

                    1 Reply Last reply
                    0

                    6/9

                    22 Jun 2013, 13:54

                    • Login

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