[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
 

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