1
\$\begingroup\$

I am new to OpenGL programming and I'm writing some basic code to display a few objects onto a screen.

I have a pyramid shape that I'm displaying, as well as a box shape that I am displaying. The pyramid shape is a class (C++), and each pyramid object creates it's own VBO (storing the points/colours). The same thing goes for the box.

The problem I'm having is that I have two shapes, and the shapes use the same vertex shader. Since I apply a model matrix for each object in the shader, the model matrix gets set for one object, but then when the other object goes to display itself it overwrites the model matrix for the previous object with it's own. So only one object has the correct model matrix after they are all done their display method.

I am also using hierarchical transformations to attach objects to each other. I have the root object storing the view/projection matrices, and the children of the hierarchy tree storing their individual model transformations. When a child wants to display itself, it walks up the tree to compute all the transformations it needs to do to itself. The problem also applies here, since the last child to be displayed will be the one whose model matrix is applied in the vertex shader.

I can't seem to figure out how to differentiate in the shader which MVP matrix to apply to which vertex. I think I'm missing something very basic here but I can't seem to figure it out... Any help would make my life a lot easier!

Edit: Is it possible that the shader is overwriting the MVP matrix in between glDrawArrays()/glDrawElements() calls?

\$\endgroup\$
1
\$\begingroup\$

Typically, the MVP matrix (along with any other matrices you might be using) are specified using uniforms, for example:

#version 330
in vec3 iPosition;  // input from vertex attribute
out vec3 vPosition; // output to fragment shader
// other inputs/outputs for colors, texture coordinates, etc. as needed

uniform mat4 uMVP;

void main()
{
    vPosition = uMVP * iPosition;
    // ...
}

The term uniform stems from the fact that they cannot be changed while a glDraw* call is running; their value is uniform across all vertices being drawn. Therefore, each object that has a distinct transform needs to have it's own draw call, and you use the glUniformMatrix API to set the correct transform prior to each draw call. You'll also need to query the location of the uniform after compiling your shader program (using glGetUniformLocation).

GLint mvp_location;

void initShaderProgram()
{
    // Generate & Compile shaders, check for errors
    // ...

    GLuint program_id = glCreateProgram();
    // Link program, check for errors
    // ...

    mvp_location = glGetUniformLocation(program_id, "uMVP");
}

void drawObject(float* mvp /* ... */ )
{
    // Ensure correct program, VAO, etc are bound.
    // ...

    glUniformMatrix4fv(mvp_location, 1, false, mvp);
    glDrawElements( /* ... */ );
}

There are alternatives to this approach which allow greater performance by batching multiple objects into a single draw call (for example, by pre-computing the world-space coordinates of static meshes on the CPU so that the same view/projection matrix can be used for them all), but it sounds like you're not anywhere close to pushing the limits of your driver or GPU, so don't worry about that unless you have to.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.