Opengl why doesn't this Shader Work?

I was trying to make a class to draw a square, this class would be instantiated one time, and every time I wanna to draw a square I would just... Square::draw(float posx, float posy ,float sizex, float sizey). the way I did it was by having a unifor vec4 on the shader where I would transmit the pos and size. And on the vbo: GLint _vertID[4] = {0,1,2,3} an indentification, so that I would know which vertex the shader was working on so I could put the right position

The problem is that it does not draw a square instead it draws randomly, some triangles.(something is wrong). I would like to know if is my logic that is wrong, or is implementation is wrong.

Here is the code:

void Square::initVertex(){
    GLint _vertID[4] = {0,1,2,3};
    GLfloat _uvs[8] = {0,0,1,0,1,1,0,1};
    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);

    glGenBuffers(2, vbo);

    glBindBuffer( GL_ARRAY_BUFFER, vbo[0]);
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(GLint), _vertID, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 1, GL_INT, false, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer( GL_ARRAY_BUFFER, vbo[1]);
    glBufferData( GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _uvs, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(1);
}

and the VertexShader: posSh is the vec4 where I pass the position every time I wanna draw a square, and vertID is the vbo that makes me know which vert is being handled

#version 150
in int vertID;
in vec2 uvs;
in vec4 posSh;
out vec2 ex_uvs;

void main(void){
    vec2 pos;

    if(vertID == 0){
        pos = vec2(posSh.x, posSh.y);
    }else if(vertID == 1){
        pos = vec2(posSh.x + posSh.z, posSh.y);
    }else if(vertID == 2){
        pos = vec2(posSh.x + posSh.z, posSh.y + posSh.w);
    }else if(vertID == 3){
        pos = vec2(posSh.x, posSh.y + posSh.w);
    }

    gl_Position = vec4(pos.x, pos.y, 1,1);
    ex_uvs = uvs;
}

1 answer

  • answered 2017-08-16 19:26 bitQUAKE

    I would prefer removing these _vertID indices. To me it looks like you are trying to save memory by using a single vec4 to render 4 vertices instead of 4x vec2 (or vec3, if required). vertID, uvs and posSh are all attributes, this means they have to have the same element count. For example:

    position: 1[x, y, z], 2[x, y, z], 3[x, y, z]
    uvCoords: 1[x, y]   , 2[x, y]   , 3[x, y]
    

    If I am right, this is not the case for posSh. This is what I see in you setup & shader code:

    vertID: 1[n]          , 2[n]      , 3[n]    , 4[n]
    uvs:    1[x, y]       , 2[x, y]   , 3[x, y] , 4[x, y]
    posSh:  1[x, y, z, w] , ???       , ???     , ???
    

    So, If this is the case, we gonna fix that now.

    • Change vbo[0] from GL_ARRAY_BUFFER to GL_ELEMENT_ARRAY_BUFFER. An element array buffer contains the indices of each element (look into the code sections above, the numbers are indices which you can specify) of the array buffer you bind. (Keep in mind, that vbo[0] will stay bound, until another GL_ELEMENT_ARRAY_BUFFER was bound)
    • Remove glVertexAttribPointer and glEnableVertexAttribArray from the GL_ELEMENT_ARRAY_BUFFER, because it just has to be bound and it already is.
    • Create a 3rd vbo in your vbo[] array which will contain all the positions of your quad. This will replace posSh. You have to set it up like the array buffer for _uvs (This will be a vec2 position)
    • Use glVertexAttribPointer and glEnableVertexAttribArray on the 3rd vbo.

    Thats how you do it. Try this code (i have not tested it yet):

    void Square::initVertex(){
        GLint _vertID[4] = {0,1,2,3};
        GLfloat _uvs[8] = {0,0,1,0,1,1,0,1};
        GLfloat _pos[8] = {0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f };
        glGenVertexArrays(1, vao); 
        glBindVertexArray(vao[0]);
    
        glGenBuffers(3, vbo); // the first index is an Element Array Buffer!
    
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo[0]);
        glBufferData( GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLint), _vertID, GL_STATIC_DRAW);
    
        glBindBuffer( GL_ARRAY_BUFFER, vbo[1]);
        glBufferData( GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _pos, GL_STATIC_DRAW);
        glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
        glEnableVertexAttribArray(0);
    
        glBindBuffer( GL_ARRAY_BUFFER, vbo[2]);
        glBufferData( GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _pos, GL_STATIC_DRAW);
        glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
        glEnableVertexAttribArray(1);
    }
    

    Shader code:

    #version 150
    in vec2 uvs;
    in vec2 pos;
    out vec2 ex_uvs;
    
    void main(void){
        gl_Position = vec4(pos.x, pos.y, 1,1);
        ex_uvs = uvs;
    }
    

    Your drawing code:

     glDrawElements(
         GL_QUADS,      // mode
         4,    // count
         GL_UNSIGNED_INT,   // type
         (void*)0           // element array buffer offset
     );
    

    I hope it helps you a little bit. Try the code, I dont know if there are any typos, I wrote it in notepad++.

    Here is an advances tutorial of how you render VBO`s correctly: Tutorial 9 : VBO Indexing