[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( QGLShader::Vertex, ":/test.vert" ); m_shader.addShaderFromSourceFile( QGLShader::Fragment, ":/test.frag" ); m_shader.link(); if ( !m_shader.bind() ) { 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 130in 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 130in 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 130in vec4 vertex;
in vec4 colour;
out vec4 colourOut;void main( void )
{
gl_Position = vertex;
colourOut = colour;
}
@
Fragment Shader:
@
#version 130in 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.