0
votes

I can't seem to get this OpenGL program to render a quad after I add a VAO.

Assuming the program is correctly initialized without errors, the following is the code that fills the VAO.

float quad[] = 
    {
        //verts        colors
        32.0f,  0.0f, 1.0f, 0.0f, 0.0f, // Top-left
        32.0f,  32.0f, 0.0f, 1.0f, 0.0f, // Top-right
        0.0f, 32.0f, 0.0f, 0.0f, 1.0f, // Bottom-right
        0.0f, 0.0f, 1.0f, 1.0f, 1.0f  // Bottom-left
    };

float textureCoords[] = 
    {
        0.0f, 0.0f, //x
        0.5f, 0.0f, //w
        0.5f, 0.5f, //y
        0.0f, 0.5f  //h
    };

float elements[] =
    {
        0,1,2,
        2,3,0
    };

//loadShaders compiles and links both shaders
GLuint shaders = loadShaders("vertexShader.c", "fragmentShader.c");
GLuint VAO, VBO[2], EBO;


glGenVertexArrays(1, &VAO);

glGenBuffers(2, VBO);
glGenBuffers(1, &EBO);

//bind VAO
glBindVertexArray(VAO);

glUseProgram(shaders);

//quad and color data
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
GLint quadAttrib = glGetAttribLocation(shaders, "quad");
glEnableVertexAttribArray(quadAttrib);//target 'quad' in shader
glVertexAttribPointer(quadAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
//color data
GLint colorAttrib = glGetAttribLocation(shaders, "color");
glEnableVertexAttribArray(colorAttrib);//target 'color' in shader
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));

//UV data
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoords), textureCoords, GL_STATIC_DRAW);
GLint uvAttrib = glGetAttribLocation(shaders, "uvCoords");//target 'uvCoords' in shaders 
glEnableVertexAttribArray(uvAttrib);
glVertexAttribPointer(uvAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);


//TEXTURES
//laod and use textures
GLuint textures[2];
glGenTextures(2, textures);


int texWidth, texHeigth;
unsigned char *image;

//activate texture 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
image = SOIL_load_image("atlas.png", &texWidth, &texHeigth, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeigth, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
glUniform1i(glGetUniformLocation(shaders, "img1"), 0);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


//element buffer data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

//UNIFORMS

//projection matrix
GLint projectionUniform = glGetUniformLocation(shaders, "projection");
glm::mat4 orthoProjection = glm::ortho( 0.0f, static_cast<float>(480), 0.0f, static_cast<float>(272));
glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, glm::value_ptr(orthoProjection));
//model view projection
GLint modelViewUniform = glGetUniformLocation(shaders, "modelView");


//unbind VAO and current shader, the VAO remembers the bound shader
glBindVertexArray(0);
glUseProgram(0);

I'm assuming that the VAO has now kept track of the following:

  • The quad buffer 'VBO[0]' and its corresponding attribPointer 'quadAttrib' to "quad" in the shader
  • The color buffer 'same VBO[0]' and its corresponding attribPointer 'colorAttrib' to 'color' in shader
  • The UV buffer 'VBO[1]' and its corresponding attribPointer 'uvAttrib' to 'uvCoords' in shader
  • That the current texture unit (0) corresponds to the loaded texture and the bind to "img1" in the fragment shader as well as its parameters
  • The EBO that is bounded to GL_ELEMENT_ARRAY_BUFFER
  • The projection matrix and its uniform
  • The handler to the model matrix
  • The shader program that was in use while the VAO was bound? Not sure, I still explicitly use the only shader program in the program

Later in the main loop, if I attempt the following, nothing gets drawn:

    // Clear the screen to black
    glClearColor(0.2f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    //draw the quad within this VAO
    glBindVertexArray(VAO);
glUseProgram(shaders);

    glm::mat4 model;

    model = glm::translate(glm::mat4(1.0f), glm::vec3(newTransX, newTransY, newTransZ));
    model = glm::scale(model, glm::vec3(newScale));

    model = glm::rotate(
        model,
        (GLfloat)clock()  / (GLfloat)CLOCKS_PER_SEC * 10000.0f,
        glm::vec3(0.0f, 0.0f, 1.0f)
    );      

// upload the uniform matrix, modelViewUniform should be already linked to the shader uniform through the VAO

    glUniformMatrix4fv(modelViewUniform, 1, GL_FALSE, glm::value_ptr(model)); 


    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glBindVertexArray(0);

    SDL_GL_SwapWindow(window);

Vertex shader:

    #version 330

in vec2 quad;
in vec3 color;
in vec2 uvCoords;

out vec3 Color;
out vec2 UVCoords;


uniform mat4 modelView;
uniform mat4 projection;

void main()
{
    Color = color;
    UVCoords = uvCoords;

    gl_Position = projection * modelView * vec4(quad, 0.0f, 1.0f);
}

Fragment shader:

    #version 330

in vec3 Color;//not in use, simple pipeline test
in vec2 UVCoords;

out vec4 outColor;

uniform sampler2D img1;


void main()
{
    vec4 finalTexture = texture(img1, UVCoords);
    outColor = finalTexture;
} 

What am I doing wrong? I know for a fact that the values in the modelView and projection matrix are correct, since the program works If I never use a VAO.

Am I assuming that the VAO remembers more than it actually does? If not, what am I doing wrong?

1
That is a lot of assumption. Have you checked the error state with glGetError(void)? Since your program works w/o the VAO have you checked the error on creation and binding?Freddy
Apparently OpenGL was optimizing the 'color' attribute since it was not being used in the shader and it wasn't binding properly. Even I change the Color to be used, the problem persists. It's not drawing anything.senex

1 Answers

1
votes

This can't be right:

float elements[] =
{
    0,1,2,
    2,3,0
};

You can't use floats for vertex indices. Based on the type you pass to glDrawElements(), this should be:

GLuint elements[] =
{
    0,1,2,
    2,3,0
};

As for the state tracked in a VAO: No, it does not hold on to all that state. It only tracks the vertex attribute setup state. From your list:

The quad buffer 'VBO[0]' and its corresponding attribPointer 'quadAttrib' to "quad" in the shader

Yes. More precisely, the VBO/pointer are associated with the location quadAttrib, and that association is tracked in the VAO. You queried quadAttrib from your shader, but the VAO state does not contain any direct association with the shader.

The color buffer 'same VBO[0]' and its corresponding attribPointer 'colorAttrib' to 'color' in shader

Same here.

The UV buffer 'VBO[1]' and its corresponding attribPointer 'uvAttrib' to 'uvCoords' in shader

And here.

That the current texture unit (0) corresponds to the loaded texture and the bind to "img1" in the fragment shader as well as its parameters

No. That has nothing to do with the vertex attribute state.

The EBO that is bounded to GL_ELEMENT_ARRAY_BUFFER

Yes.

The projection matrix and its uniform

No. The uniform value is part of the program state.

The handler to the model matrix

No.

The shader program that was in use while the VAO was bound?

No.