Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. [SOLVED] Simple Example of 3d Cube inside SceneGraph needed
QtWS25 Last Chance

[SOLVED] Simple Example of 3d Cube inside SceneGraph needed

Scheduled Pinned Locked Moved QML and Qt Quick
10 Posts 3 Posters 3.6k 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
    sgrahovac
    wrote on last edited by
    #1

    I was wondering if anyone could forward a link and/or a 3d OpenGL example using a custom QtQuick component that might render something simple like a cube. I am hoping to use native OpenGL to render a 3d opengl object in the background (and not Qt3d since it is under heavy development) and QtQuick components in the foreground. I am aware of the "OpenGL under QML" example, but that example unfortunately does not seem to make it clear how to render 3d perspective lines.

    I would greatly appreciate any help this!

    Best regards,

    Steve

    1 Reply Last reply
    0
    • D Offline
      D Offline
      dasRicardo
      wrote on last edited by
      #2

      @
      //replace this:
      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
      //with this:
      glDrawArrays(GL_LINES, 0, 4);
      @

      But it's not a qtquick problem it's an opengl problem so "here....":http://www.opengl-tutorial.org/

      **Sorry for my english :)

      PLEASE ADD [SOLVED] TO YOUR THREAD TITLE IF IT'S SOLVED.**

      1 Reply Last reply
      0
      • S Offline
        S Offline
        sgrahovac
        wrote on last edited by
        #3

        Thanks Ricardo, I will give your suggestion a try and will post the code I have tried. The last time I tried though, I had trouble setting the viewport up from othogonal to perspective. My short term goal is to render a wireframe cube.

        Thanks for the link! I understand its not a functional QtQuick issue, however it does seem like a bit of a documentation issue that there are no examples that demonstrate OpenGL rendering of something more useful like a cube.

        Steve

        1 Reply Last reply
        0
        • S Offline
          S Offline
          sgrahovac
          wrote on last edited by
          #4

          For simplicity, I'm currently trying to render a square 45 degrees around the x-axis. Currently it renders like a blue square rather than rotated square. Specifically, when I use the following line in my paint() function, it fails to rotate:

          glRotatef(45,1,0,0);
          

          If someone happens to notice where I am making a mistake, this would be hugely appreciated.

          Here is my QML file:

          import QtQuick 2.0
          import OpenGLUnderQML 1.0

          Item {
          width: 500
          height: 500

          Squircle {
          }
          

          }

          Here is my modified squircle.cpp file (please see paint() function for where I need help):

          @
          #include "squircle.h"
          #include <QtQuick/qquickwindow.h>
          #include <QtGui/QOpenGLShaderProgram>
          #include <QtGui/QOpenGLContext>

          //! [7]
          Squircle::Squircle()
          : m_program(0)
          , m_t(0)
          , m_thread_t(0)
          {
          connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)));
          }
          //! [7]

          //! [8]
          void Squircle::setT(qreal t)
          {
          if (t == m_t)
          return;
          m_t = t;
          emit tChanged();
          if (window())
          window()->update();
          }
          //! [8]

          //! [1]
          void Squircle::handleWindowChanged(QQuickWindow *win)
          {
          if (win) {
          //! [1]
          // Connect the beforeRendering signal to our paint function.
          // Since this call is executed on the rendering thread it must be
          // a Qt::DirectConnection
          //! [2]
          connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
          connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection);
          //! [2]

              // If we allow QML to do the clearing, they would clear what we paint
              // and nothing would show.
          

          //! [3]
          win->setClearBeforeRendering(false);
          }
          }

          //! [3] //! [4]
          void Squircle::paint()
          {
          if (!m_program) {
          m_program = new QOpenGLShaderProgram();
          m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
          "attribute highp vec4 vertices;"
          "varying highp vec2 coords;"
          "void main() {"
          " gl_Position = vertices;"
          " coords = vertices.xy;"
          "}");
          m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
          "uniform lowp float t;"
          "varying highp vec2 coords;"
          "void main() {"
          " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);"
          "}");

              m_program->bindAttributeLocation("vertices", 0);
              m_program->link();
          
              connect(window()->openglContext(), SIGNAL(aboutToBeDestroyed()),
                      this, SLOT(cleanup()), Qt::DirectConnection);
          }
          

          //! [4] //! [5]
          m_program->bind();

          m_program->enableAttributeArray(0);
          
          float values[] = {
              -.5, -.5,0, // bottom line
              .5, -.5,0,
              -.5, .5,0, // top line
              .5, .5,0,
              .5, .5,0, // right line
              .5, -.5,0,
              -.5, -.5,0, // left line
              -.5, .5,0,
          };
          
          
          m_program->setAttributeArray(0, GL_FLOAT, values, 3);
          

          // m_program->setUniformValue("t", (float) m_thread_t);

          qreal ratio = window()->devicePixelRatio();
          int w = int(ratio * window()->width());
          int h = int(ratio * window()->height());
          glViewport(0, 0, w, h);
          qDebug()<<"w "<<w<<"h"<<h<<"width"<<window()->width()<<"height"<<window()->height();
          
          glDisable(GL_DEPTH_TEST);
          
          // trying to rotate 45 degrees around the x-axis, but it doesn't work
          glRotatef(45,1,0,0);
          
          glDrawArrays(GL_LINES, 0,8);
          
          
          m_program->disableAttributeArray(0);
          m_program->release();
          

          }

          //! [6]
          void Squircle::cleanup()
          {
          if (m_program) {
          delete m_program;
          m_program = 0;
          }
          }
          //! [6]

          //! [9]
          void Squircle::sync()
          {
          m_thread_t = m_t;
          }
          //! [9]

          @

          1 Reply Last reply
          0
          • S Offline
            S Offline
            sgrahovac
            wrote on last edited by
            #5

            I just got a lot closer. Now I am able to rotate on the y axis. The trick was to multiply by a matrix in my vertex shader.

            My last remaining problem is getting my rotated squared to render in a perspective mode rather than an orthogonal fashion. In other words, when I rotate by 45 degrees, my rectangle becomes less wide. However, what I want to happen is I want the left side of my square to get taller and right side of my square to get shorter after rotation (hope that makes sense).

            Does anyone know of a magic initialization function to setup perspective mode or do I have to modify the vertex shader again?

            Here is my new code (I only included paint() function and newly added initView() function this time):

            @

            // added to help set perspective
            void Squircle::initView()
            {
            qreal ratio = window()->devicePixelRatio();
            int w = int(ratio * window()->width());
            int h = int(ratio * window()->height());
            glViewport(0, 0, w, h);

            // Calculate aspect ratio
            qreal aspect = qreal(w) / qreal(h ? h : 1);
            
            // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
            const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;
            
            // Reset projection
            projection.setToIdentity();
            
            // Set perspective projection
            projection.perspective(fov, aspect, zNear, zFar);
            

            }

            //! [3] //! [4]
            void Squircle::paint()
            {
            if (!m_program) {
            m_program = new QOpenGLShaderProgram();
            m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
            "attribute highp vec4 vertices;"
            // added for rotation
            "uniform mat4 mvp_matrix;"
            "varying highp vec2 coords;"
            "void main() {"
            " gl_Position = vertices * mvp_matrix;"
            " coords = vertices.xy;"
            "}");
            m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
            "uniform lowp float t;"
            "varying highp vec2 coords;"
            "void main() {"
            " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);"
            "}");

                m_program->bindAttributeLocation("vertices", 0);
                m_program->link();
                initView();
                connect(window()->openglContext(), SIGNAL(aboutToBeDestroyed()),
                        this, SLOT(cleanup()), Qt::DirectConnection);
            }
            

            //! [4] //! [5]
            m_program->bind();

            m_program->enableAttributeArray(0);
            
            float values[] = {
                -.5, -.5,0, // bottom line
                .5, -.5,0,
                -.5, .5,0, // top line
                .5, .5,0,
                .5, .5,0, // right line
                .5, -.5,0,
                -.5, -.5,0, // left line
                -.5, .5,0,
            };
            
            
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glEnable(GL_DEPTH_TEST);
            glEnable(GL_CULL_FACE);
            
            m_program->setAttributeArray(0, GL_FLOAT, values, 3);
            

            // m_program->setUniformValue("t", (float) m_thread_t);
            QMatrix4x4 matrix;
            matrix.translate(0.0, 0.0, -5.0);
            matrix.rotate(45,0,1,0);
            m_program->setUniformValue("mvp_matrix", projection * matrix );

            glDrawArrays(GL_LINES, 0,8);
            
            
            m_program->disableAttributeArray(0);
            m_program->release();
            

            }

            @

            1 Reply Last reply
            0
            • S Offline
              S Offline
              sgrahovac
              wrote on last edited by
              #6

              My issue is now solved. The issue was in the following line in the vertex shader:
              " gl_Position = vertices * mvp_matrix;"

              The matrix has to be on the left side as matrix operations are not commutative.

              So the line should read:
              " gl_Position = mvp_matrix * vertices;"

              Note: This code does not create a cube, but does create a perspective rendered rotated square which I think is close enough to meet the general goal of this topic.

              For the sake of completeness, the full perspective based OpenGL QtQuick component now has the following code;

              @

              #include "squircle.h"
              #include <QtQuick/qquickwindow.h>
              #include <QtGui/QOpenGLShaderProgram>
              #include <QtGui/QOpenGLContext>

              //! [7]
              Squircle::Squircle()
              : m_program(0)
              , m_t(0)
              , m_thread_t(0)
              {
              connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)));
              }
              //! [7]

              //! [8]
              void Squircle::setT(qreal t)
              {
              if (t == m_t)
              return;
              m_t = t;
              emit tChanged();
              if (window())
              window()->update();
              }
              //! [8]

              //! [1]
              void Squircle::handleWindowChanged(QQuickWindow *win)
              {
              if (win) {
              //! [1]
              // Connect the beforeRendering signal to our paint function.
              // Since this call is executed on the rendering thread it must be
              // a Qt::DirectConnection
              //! [2]
              connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
              connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection);
              //! [2]

                  // If we allow QML to do the clearing, they would clear what we paint
                  // and nothing would show.
              

              //! [3]
              win->setClearBeforeRendering(false);
              }
              }

              // added to help set perspective
              void Squircle::initView()
              {
              qreal ratio = window()->devicePixelRatio();
              int w = int(ratio * window()->width());
              int h = int(ratio * window()->height());
              glViewport(0, 0, w, h);
              glMatrixMode (GL_PROJECTION);
              glMatrixMode(GL_MODELVIEW);
              // Calculate aspect ratio
              qreal aspect = qreal(w) / qreal(h ? h : 1);

              // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
              const qreal zNear = 3.0, zFar = 700.0, fov = 45.0;
              
              // Reset projection
              projection.setToIdentity();
              //modelMatrix.setToIdentity();
              // Set perspective projection
              

              // projection.perspective(fov, aspect, zNear, zFar);
              projection.frustum(-aspect,aspect,-1,1,zNear,zFar);

              }

              //! [3] //! [4]
              void Squircle::paint()
              {
              if (!m_program) {
              m_program = new QOpenGLShaderProgram();
              m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
              "attribute highp vec4 vertices;"
              // added for rotation
              "uniform mat4 mvp_matrix;"
              "varying highp vec2 coords;"
              "void main() {"
              " gl_Position = mvp_matrix * vertices;"
              " coords = vertices.xy;"
              "}");
              m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
              "uniform lowp float t;"
              "varying highp vec2 coords;"
              "void main() {"
              " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);"
              "}");

                  m_program->bindAttributeLocation("vertices", 0);
                  m_program->link();
                  initView();
                  connect(window()->openglContext(), SIGNAL(aboutToBeDestroyed()),
                          this, SLOT(cleanup()), Qt::DirectConnection);
              }
              

              //! [4] //! [5]
              m_program->bind();

              m_program->enableAttributeArray(0);
              
              float values[] = {
                  -.5, -.5,0, // bottom line
                  .5, -.5,0,
                  -.5, .5,0, // top line
                  .5, .5,0,
                  .5, .5,0, // right line
                  .5, -.5,0,
                  -.5, -.5,0, // left line
                  -.5, .5,0,
              };
              
              
              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
              glEnable(GL_DEPTH_TEST);
              glEnable(GL_CULL_FACE);
              
              m_program->setAttributeArray(0, GL_FLOAT, values, 3);
              

              // m_program->setUniformValue("t", (float) m_thread_t);
              QMatrix4x4 matrix;
              matrix.translate(0.0, 0.0, -5.0);
              matrix.rotate(45,0,1,0);
              m_program->setUniformValue("mvp_matrix", projection * matrix );

              glDrawArrays(GL_LINES, 0,8);
              
              
              m_program->disableAttributeArray(0);
              m_program->release();
              

              }

              //! [6]
              void Squircle::cleanup()
              {
              if (m_program) {
              delete m_program;
              m_program = 0;
              }
              }
              //! [6]

              //! [9]
              void Squircle::sync()
              {
              m_thread_t = m_t;
              }
              //! [9]
              //!
              @

              1 Reply Last reply
              0
              • S Offline
                S Offline
                sgrahovac
                wrote on last edited by
                #7

                How do I mark this as solved?

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

                  That's done by editing your first post and modifying the title by hand

                  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
                  • S Offline
                    S Offline
                    sgrahovac
                    wrote on last edited by
                    #9

                    Thanks SGaist!

                    I'm a bit surprised there isn't a "Mark as Solved" checkbox somewhere, but editing the topic also works.

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

                      The forum is using an old system that's not easy to hack to add that feature, but the request is known :)

                      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

                      • Login

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