0
votes

I have a code that initially had one shader (ourShader), one VAO and one VBO. It would render a scene with a textured cube and its reflection on the ground using Stencil testing. Now, I wanted to add a framebuffer for post-processing so I needed a second shader. I added a second shader (screenShader) and a second VBO. I don't use them in my drawing yet, but the simple fact that I'm adding them makes my code render a black, red triangle instead of the usual scene.

My code looks like this :

    Shader ourShader(string("core.vs"), string("core.frag")); // shader class creating a shader program from vertex shader and fragment shader source files.
    Shader screenShader(string("core2.vs"), string("core2.frag"));

    // Setting up attributes, VAO, VBO
    GLuint VAO;
    array<GLuint, 2> VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(2, &VBO[0]);

    glBindVertexArray(VAO);

    // Data for first shader and first VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verticesCube), verticesCube, GL_STATIC_DRAW); 

    GLint posAttribLoc = glGetAttribLocation(ourShader.Program, "position");
    glVertexAttribPointer(posAttribLoc, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); // specify (to the active VAO) how to retrieve the values for the attribute "position" from the data stored ("vertices" here) on the active VBO (GPU)
    glEnableVertexAttribArray(posAttribLoc); // enable attribute for rendering

    GLint colAttribLoc = glGetAttribLocation(ourShader.Program, "color");
    glVertexAttribPointer(colAttribLoc, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(colAttribLoc);

    GLint texAttribLoc = glGetAttribLocation(ourShader.Program, "texCoord");
    glVertexAttribPointer(texAttribLoc, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(texAttribLoc);

    // ##### PART GIVING A WEIRD RESULT #####
    // Data for second shader and second VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verticesRectangle), verticesRectangle, GL_STATIC_DRAW);

    GLint posAttribLoc2 = glGetAttribLocation(screenShader.Program, "position");
    glVertexAttribPointer(posAttribLoc2, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0); // specify (to the active VAO) how to retrieve the values for the attribute "position" from the data stored ("vertices" here) on the active VBO (GPU)
    glEnableVertexAttribArray(posAttribLoc2); // enable attribute for rendering

    GLint texAttribLoc2 = glGetAttribLocation(screenShader.Program, "texCoord");
    glVertexAttribPointer(texAttribLoc2, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
    glEnableVertexAttribArray(texAttribLoc2);
   // ##### END #####

    // Setting up texture that will be used for the first shader
    GLuint texture;
    int width, height;
    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture); // makes "texture" the current texture and attaches it to texture unit 0

    // Set the wrapping 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    // Set the filtering 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);
    SOIL_free_image_data(image);

    // Unbind VBO, texture before main loop
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0); 
    glfwSwapInterval(1);
    glfwSetKeyCallback(window, Input::keyCallback); // Input is a singleton class handling inputs. It works well.
    glfwSetCursorPosCallback(window, Input::mouseCallback);
    glfwSetScrollCallback(window, Input::scrollCallback);

    while (glfwWindowShouldClose(window) == GLFW_FALSE) {
        // MAIN LOOP
        // ...
    }
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(2, &VBO[0]);

The mainloop is not important I think. What I want to say is that if I remove the few lines dealing with the the second VBO, then the scene renders well. Otherwise, I get a weird-colored triangle.

And my two shaders use those source files for their respective vertex shader and fragment shader. By the way, I get no compilation errors from my shaders.

core.vs :

#version 330 core
in vec3 position;
in vec2 texCoord;
in vec3 color;

out vec2 TexCoord;
out vec3 Color;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection*view*model*vec4(position, 1.0);
    TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
    Color = color;
}

core.frag :

#version 330 core
in vec2 TexCoord;
in vec3 Color;

out vec4 outColor;
uniform sampler2D ourTexture0;

void main()
{
    outColor = vec4(Color, 1)*texture(ourTexture0, TexCoord);
}

core2.vs :

#version 330 core
in vec2 position;
in vec2 texCoord;
out vec2 TexCoord;
void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
    TexCoord = texCoord;
}

core2.frag :

#version 330 core
in vec2 TexCoord;
out vec4 outColor;
uniform sampler2D texFramebuffer;
void main()
{
    outColor = texture(texFramebuffer, TexCoord);
}

The vertices look like this (but only the way to read them is important) :

    GLfloat verticesRectangle[] = {
        // position     // texture coordinates
        -0.5f, -0.5f,   0.0f, 0.0f,     
        0.5f, -0.5f,    1.0f, 0.0f,     
        -0.5f, 0.5f,    0.0f, 1.0f,     
        0.5f, 0.5f,     1.0f, 1.0f      
    };

    GLfloat verticesCube[] = {
        // position          // color          // texture coordinates
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,

        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,

        -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,

        0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,

        -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,

        -1.0f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // reflection surface // not a part of the cube itself
        -1.0f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
        1.0f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        -1.0f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
    };

I've already looked at Binding a second vertex buffer seems to spoil my first vertex buffer, OpenGL OES ios 5.1 but the person had this problem because he didn't use his VAO correctly.

1
What's the point of using VAOs if you only have one?Frank

1 Answers

2
votes

Most probably two of your attribute locations have the same value. Since you use just one VAO, you override some of the bindings. The correct way of using multiple independent geometries is to use on VAO per geometry.

The correct code has to look somehow like this:

glBindVertexArray(vao1);
glBindBuffer(VBO[0])
glVertexAttribPointer...
glEnableVertexAttribArray...
//Setup all attributes for first VBO

glBindVertexArray(vao2);
glBindBuffer(VBO[1])
glVertexAttribPointer...
glEnableVertexAttribArray...
//Setup all attributes for second VBO

When rendering do the following:

glBindVertexArray(vao1);
glDraw*... //Draw VAO1

glBindVertexArray(vao2);
glDraw*.... //Draw VAO2