Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[Solved] QGLShaderProgram problem getting object to show with OpenGL 3.0



  • Hi,

    I wanted to try OpenGL programming using Qt. However, I have problems getting an image to show up. I took some pieces of code that I found in the documentation but I don't know where the problem is. My only guess is that I'm not sending the attribute data correctly.

    What I'm attempting to do is to draw a triangle with a different colour near each vertex.

    The code that I have for it is shown below (Note that m_shader is the QGLShaderProgram object).
    @
    GLRenderer::GLRenderer( const QGLFormat& format, QWidget* parent )
    : QGLWidget( format, parent )
    {
    }

    void GLRenderer::initializeGL()
    {
    QGLFormat glFormat = QGLWidget::format();
    if ( !glFormat.sampleBuffers() )
    qWarning() << "Could not enable sample buffers";

    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
    
    m_shader.addShaderFromSourceFile&#40; QGLShader::Vertex, ":/test.vert" &#41;;
    m_shader.addShaderFromSourceFile( QGLShader::Fragment, ":/test.frag" &#41;;
    m_shader.link(&#41;;
    
    if ( !m_shader.bind(&#41; )
    {
        qWarning() << "Could not bind shader program";
        return;
    }
    
    GLfloat points[] = { -0.5f, -0.5f, 0.0f,
                         -0.5f,  0.5f, 0.0f,
                          0.5f,  0.5f, 0.0f };
    GLfloat colors[] = { 1.0f, 0.0f, 0.0f,
                         0.0f, 1.0f, 0.0f,
                         1.0f, 1.0f, 1.0f };
    
    int vertexLocation = m_shader.attributeLocation("vertex");
    int colourLocation = m_shader.attributeLocation("color_in");
    
    m_shader.setAttributeArray(vertexLocation, points, 3);
    m_shader.setAttributeArray(colourLocation, colors, 3);
    m_shader.enableAttributeArray(vertexLocation);
    m_shader.enableAttributeArray(colourLocation);
    

    }

    void GLRenderer::resizeGL( int w, int h )
    {
    glViewport( 0, 0, w, h );
    }

    void GLRenderer::paintGL()
    {
    // Clear the buffer with the current clearing color
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    // Draw stuff
    glDrawArrays( GL_TRIANGLES, 0, 3 );
    

    }
    @

    The vertex shader I wrote is
    @
    #version 130

    in vec3 vertex;
    in vec3 color_in;
    out vec3 color;

    void main( void )
    {
    gl_Position = vec4(vertex, 1.0);
    color = vec3(color_in);
    }
    @

    The fragment shader I wrote is
    @
    #version 130

    in vec3 color;
    out vec4 fragColor;

    void main( void )
    {
    fragColor = vec4(color, 1.0);
    }
    @

    And in case any of you were wondering where I used the GLRenderer object I wrote this piece of code in the main file
    @
    QGLFormat glFormat;
    glFormat.setVersion( 3, 0 );
    glFormat.setProfile( QGLFormat::CoreProfile );
    glFormat.setSampleBuffers( true );

    GLRenderer w( glFormat );
    w.show();
    

    @

    I'm fairly new to this graphics stuff but I am really interested in using OpenGL with Qt so if any of you can offer any help or tips on fixing my program or making it better I would very much appreciate it.

    Thank you in advance.

    Sincerely,
    Bobby



  • This "article":http://developer.qt.nokia.com/wiki/How_to_use_OpenGL_Core_Profile_with_Qt should get you up and running with a basic OpenGL 3.3 context.



  • Thanks for the reply,

    I have used some parts of the code to help me understand and I believe that I have found a solution. However I am unsure if my solution is the best way to go about it.

    Most of what I changed is in the initializeGL() method:
    @
    void GLRenderer::initializeGL()
    {
    QGLFormat glFormat = QGLWidget::format();
    if ( !glFormat.sampleBuffers() )
    qWarning() << "Could not enable sample buffers";

    // Set the clear color to black
    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
    
    // Prepare a complete shader program...
    if ( !prepareShaderProgram( ":/test.vert", ":/test.frag" ) )
        return;
    
    // Data contains the vertex positions and the corresponding
    // colours.
    GLfloat vertexData[] = { -0.5f, -0.5f, 0.0f, 1.0f,
                             -0.5f,  0.5f, 0.0f, 1.0f,
                              0.5f,  0.5f, 0.0f, 1.0f,
                              1.0f,  0.0f, 0.0f, 1.0f,
                              0.0f,  1.0f, 0.0f, 1.0f,
                              0.0f,  0.0f, 1.0f, 1.0f, };
    
    m_vertexBuffer.create();
    m_vertexBuffer.setUsagePattern( QGLBuffer::StaticDraw );
    if ( !m_vertexBuffer.bind() )
    {
       qWarning() << "Could not bind vertex buffer to the context";
       return;
    }
    m_vertexBuffer.allocate( vertexData, sizeof(vertexData) );
    
    // Bind the shader program so that we can associate variables from
    // our application to the shaders
    if ( !m_shader.bind() )
    {
       qWarning() << "Could not bind shader program to context";
       return;
    }
    
    // Enable the "vertex" and "colour" attribute to bind it to our currently bound
    // vertex buffer.
    m_shader.setAttributeBuffer( "vertex", GL_FLOAT, 0, 4 );
    m_shader.setAttributeBuffer("colour", GL_FLOAT, 3 * 4*sizeof(float), 4);
    m_shader.enableAttributeArray( "vertex" );
    m_shader.enableAttributeArray("colour");
    

    }
    @

    As you can probably see I have combined the vertex position and colours into one array. I have also added a bit of code
    @
    //Set offset to start at the fourth 4-component vector (1.0f, 0.0f, 0.0f, 1.0f)
    m_shader.setAttributeBuffer("colour", GL_FLOAT, 3 * 4*sizeof(float), 4);
    m_shader.enableAttributeArray("colour");
    @

    I made some minor changes to the vertex and fragment shaders because I used 4-component vectors instead of the 3-component vectors I used before.
    Vertex Shader:
    @
    #version 130

    in vec4 vertex;
    in vec4 colour;
    out vec4 colourOut;

    void main( void )
    {
    gl_Position = vertex;
    colourOut = colour;
    }
    @
    Fragment Shader:
    @
    #version 130

    in vec4 colourOut;
    out vec4 fragColor;

    void main( void )
    {
    fragColor = colourOut;
    }
    @
    That is what I did to get the colours in. However, I am not sure if joining the position and colour arrays into one array was the best solution. I would prefer if I could keep the two separate but I do not know how do it.



  • Wait, I think I found a way to keep the position data and colour data separate.

    Just split the vertexData array
    @
    GLfloat position[] = { -0.5f, -0.5f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.0f, 1.0f,
    0.5f, 0.5f, 0.0f, 1.0f, };
    GLfloat colour[] = { 1.0f, 0.0f, 0.0f, 1.0f,
    0.0f, 1.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 1.0f, 1.0f };
    @

    Then replace the line
    @
    m_vertexBuffer.allocate( vertexData, sizeof(vertexData) );
    @
    with several lines shown below
    @
    m_vertexBuffer.allocate( sizeof(position) + sizeof(colour) );

    m_vertexBuffer.write(0, position, sizeof(position));
    m_vertexBuffer.write(sizeof(position), colour, sizeof(colour));
    

    @

    I think this is a better method than before, but if anyone knows how to do it better I would be glad to hear from you.



  • Just use two vertex buffer objects. Here is a similar example from another demo I have where I have used separate VBOs for the vertices and the colors. I call these functions from initialiseGL().

    @
    bool GLWidget::prepareVertexBuffer()
    {
    float vertices[] = { -600.0f, -337.0f, 0.0f, 1.0f,
    -600.0f, 337.0f, 0.0f, 1.0f,
    600.0f, 337.0f, 0.0f, 1.0f,
    600.0f, -337.0f, 0.0f, 1.0f };
    m_vertexBuffer.create();
    m_vertexBuffer.setUsagePattern( QGLBuffer::StaticDraw );
    if ( !m_vertexBuffer.bind() )
    {
    qDebug() << "Could not bind vertex buffer to the context";
    return false;
    }
    m_vertexBuffer.allocate( vertices, 4 * 4 * sizeof( float ) );
    return true;
    }

    bool GLWidget::prepareColorsBuffer()
    {
    float colors[] = { 1.0f, 0.0f, 0.0f, 1.0f
    0.0f, 1.0f, 0.0f, 1.0f
    0.0f, 0.0f, 1.0f, 1.0f
    1.0f, 1.0f, 1.0f, 1.0f };
    m_colorBuffer.create();
    m_colorBuffer.setUsagePattern( QGLBuffer::StaticDraw );
    if ( !m_colorBuffer.bind() )
    {
    qDebug() << "Could not bind colors buffer to the context";
    return false;
    }
    m_colorBuffer.allocate( colors, 4 * 4 * sizeof( float ) );
    return true;
    }
    @

    Then later on in initialiseGL() you can do something like this:

    @
    // Enable the "vertex" attribute to bind it to our vertex buffer
    m_vertexBuffer.bind();
    m_shader.setAttributeBuffer( "vertex", GL_FLOAT, 0, 4 );
    m_shader.enableAttributeArray( "vertex" );

    // Enable the "color" attribute to bind it to our colors buffer
    m_colorBuffer.bind();
    m_shader.setAttributeBuffer( "color", GL_FLOAT, 0, 4 );
    m_shader.enableAttributeArray( "color" );
    

    @

    That way when you call glDrawArrays() your shaders will get passed in all the enabled attribute arrays (vertex and color here) in one go.



  • I see, that does seem better than my idea. Thank you very much. Your help is very much appreciated.


Log in to reply