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



  • 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



  • @
    //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/



  • 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



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

    @



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

    }

    @



  • 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]
    //!
    @



  • How do I mark this as solved?


  • Lifetime Qt Champion

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



  • Thanks SGaist!

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


  • Lifetime Qt Champion

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


Log in to reply
 

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