0
votes

I am trying to render an object using GLM for matrix transformations, but I'm getting this:

White rectangle is rendered instead of the object

EDIT: Forgot to mention that the object I'm trying to render is a simple Torus.

I did a lot of digging around and one thing I noticed is glGetUniformLocation(program, "mvp") returns -1. The docs says it will return -1 if the uniform variable isn't used in the shader, even if it is declared. As you can see below, it has been declared and is being used in the vertex shader. I've checked against program to make sure it is valid, and such.

So my questions are:

Question 1:

Why is glGetUniformLocation(program, "mvp") returning -1 even though it is declared and is being used in the vertex shader?

Question 2: (Which I think may be related to Q1)

Another thing I'm not particularly clear on. My GameObject class has a struct called Mesh with variables GLuint vao and GLuint[4] vbo (Vertex Array Object) and (Vertex Buffer Object). I am using Assimp, and my GameObject class is based on this tutorial. The meshes are rendered in the same way as the tutorial, using:

glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, elementCount, GL_UNSIGNED_INT, NULL);

I'm not sure how VAO's and VBO's work. What I've found is that VAO's are used if you want access to the vertex arrays throughout your program, and VBO's are used if you just want to send it to the graphics card and not touch it again (Correct me if I'm wrong here). So why does the tutorial mix them? In the constructor for a mesh, it creates and binds a VAO then doesn't touch it for the rest of the constructor (unless creating and binding VBO's have an effect on the currently bound VAO). It then goes on and creates and binds VBO's for the vertex buffer, normal buffer, texture coordinate buffer, and index buffer. To render the object it binds the VAO and calls glDrawElements. What I'm confused about is how/where does OpenGL access the VBO's, and if it can't with the setup in the tutorial, which I'm pretty sure it can, what needs to change?

Source

void GameObject::render() {
    GLuint program = material->shader->program;
    glUseProgram(program);
    glm::mat4 mvp = Game::camera->mvpMatrix(this->position);

    GLuint mvpLoc = glGetUniformLocation(program, "mvp");
    printf("MVP Location: %d\n", mvpLoc); // prints -1
    glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, &mvp[0][0]);
    for (unsigned int i = 0; i < meshes.size(); i++) {
        meshes.at(i)->render(); // renders element array for each mesh in the GameObject
    }
}

Vertex shader (simple unlit red color):

#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 mvp;

out vec3 vertColor;

void main(void) {
    gl_Position = mvp * vec4(position, 1);
    vertColor = vec3(1, 0, 0);
}

Fragment shader:

#version 330 core
in vec3 vertColor;
out vec3 color;

void main(void) {
    color = vertColor;
}
1
if you get -1, it's possibly because your shader is not compiled/linked. did that step work ok?Bahbar
Yes, I checked that the shaders compiles and the program links.Alex Mohr
well if that's the case I'm stumped. I can only see a problem in the loading/compiling/linking part of the code to explain this though (are you sure you pass the right shaders to the program? is the program variable set properly? and so on?)Bahbar
Check you are loading the correct shader, iirc a 'blank' shader will still compile/link correctly and then of course break when you try to set uniforms.Lionel
I checked that I'm using the correct shader everywhere. Is there something weird with the OpenGL context? (See my comment on foundry's answer below)Alex Mohr

1 Answers

2
votes

Question 1

You've pretty much answered this one yourself. glGetUniformLocation(program, name) gets the location of the uniform "mvp" in the shader program program and returns -1 if the uniform is not declared (or not used: if you don't use it, it doesn't get compiled in). Your shader does declare and use mvp, which strongly suggests there is an issue with compiling the program. Are you sure you are using this shader in the program?

Question 2

A VBO stores the data values that the GPU will use. These could be colour values, normals, texture coordinates, whatever you like. A VAO is used to express the layout of your VBOs - think of it like a map, indicating to your program where to find the data in the VBOs.

The example program does touch the VAO whenever it calls glVertexAttribPointer, e.g.

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

This is not related to your missing uniform.