Search code examples
c++qtopenglglsl

OpenGL mix fix pipeline and shader program (Qt)


I'm working on a old code that used fixed function pipeline, the scene is a bit complex but works fine. For the sake of simplicity, I replaced it with one blue triangle :

void RenduOpenGL::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    glViewport(0, 0, this->width(), this->height());

    glBegin(GL_TRIANGLES);
    glColor3d(0,0,1);
    glVertex3d(0.7, 0.7, 0.0);
    glVertex3d(-0.5, 0.7, 0.0);
    glVertex3d(0.1, -0.7, 0.0);
    glEnd();
}

Now I want to add shaders for new elements in the scene but keep the old elements of the scene like this blue triangle.

I've read here that I can mix the two to produce a scene containing the first then the second.

Therefore I want to add this code after the blue triangle :

float vertices[] = {
    0.6, 0.6, 0.0,
    -0.6, 0.6, 0.0,
    0.0, -0.6, 0.0,
};

vbo.create();  // glGenBuffers(...);
vbo.bind();  // glBindBuffer(GL_ARRAY_BUFFER, vbo);
vbo.allocate(vertices, sizeof(vertices));  // glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), vertices, GL_STATIC_DRAW);
vbo.release();  // glBindBuffer(GL_ARRAY_BUFFER, 0);

prog.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/base.vert");
prog.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/base.frag");

vao.create();  // glGenVertexArrays(...)
vao.bind(); // glBindVertexArray(vao);

prog.enableAttributeArray("position");  // glEnableVertexAttribArray(VAO_position);
prog.setAttributeBuffer("position", GL_FLOAT, 0, 3); // (offset, size, stride=0); // glVertexAttribPointer(VAO_position, 4, GL_FLOAT, False, 0, reinterpret_cast<const void *>(offset)(0)); (False,
vao.release();  // glBindVertexArray(0);

// draw the triangle

prog.bind();  // glUseProgram(shader_program);
vao.bind();  // glBindVertexArray(vertex_array_object);

glDrawArrays(GL_TRIANGLES, 0, 3);

vao.release();  // glBindVertexArray(0);
prog.release();  // glUseProgram(0);

I use Qt to call the openGL functions, the corresponding opengl functions are in comments.

My shaders are very basic :

// base.vert
#version 330
// vertex shader

in vec3 position;

void main() {
    gl_Position = vec4(position.xyz, 1);
}
// base.frag
#version 330
// fragment shader

out vec4 pixel;

void main() {
    pixel = vec4(1, 0.5, 0, 1);
}

That is supposed to draw an orange triangle, but when I put the code after the blue triangle code, I don't see the orange triangle created from shaders.


Solution

  • Short (with code) answer: The VBO and the prog.enableAttributeArray and prog.setAttributeBuffer should be in the VAO.

    Something along the lines:

    float vertices[] = {
        0.6, 0.6, 0.0,
        -0.6, 0.6, 0.0,
        0.0, -0.6, 0.0,
    };
    
    prog.bind();  // glUseProgram(shader_program);
    
    vao.create();  // glGenVertexArrays(...)
    vao.bind(); // glBindVertexArray(vao);
    
    vbo.create();  // glGenBuffers(...);
    vbo.bind();  // glBindBuffer(GL_ARRAY_BUFFER, vbo);
    vbo.allocate(vertices, sizeof(vertices));  // glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), vertices, GL_STATIC_DRAW);
    //vbo.release();  // glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    prog.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/base.vert");
    prog.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/base.frag");
    
    prog.enableAttributeArray("position");  // glEnableVertexAttribArray(VAO_position);
    prog.setAttributeBuffer("position", GL_FLOAT, 0, 3); // (offset, size, stride=0); // glVertexAttribPointer(VAO_position, 4, GL_FLOAT, False, 0, reinterpret_cast<const void *>(offset)(0)); (False,
    vao.release();  // glBindVertexArray(0);
    
    // draw the triangle
    
    prog.bind();  // glUseProgram(shader_program);
    vao.bind();  // glBindVertexArray(vertex_array_object);
    
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    vao.release();  // glBindVertexArray(0);
    prog.release();  // glUseProgram(0);
    

    Not so long but textual answer: OpenGL is a state machine, you need to link together: the VBO and how to read its data, inside the VAO. However, IMHO, Qt people have sadly chosen their abstractions poorly: enableAttributeArray and setAttributeBuffer would be clearer as members of the VAO class instead of the prog class.