Search code examples
c++openglglslglm-mathvbo

OpenGL draw points with different colors, vertex location and vertex color in different VBOs?


I would like to draw different points with different colors. I put the vertex location data and color data in different VBOs, such as below:

Here is my C++ code:

    m_Points.push_back(glm::vec3(4, 0, 0));
    m_Points.push_back(glm::vec3(0, 2, 0));
    m_Points.push_back(glm::vec3(0, 0, 3));
    m_Points.push_back(glm::vec3(0, 0, 6));

    m_Colors.push_back(glm::vec3(0, 1.0, 0));
    m_Colors.push_back(glm::vec3(1.0, 0, 0));
    m_Colors.push_back(glm::vec3(0, 0, 1.0));
    m_Colors.push_back(glm::vec3(1.0, 1.0, 0));

    glEnable(GL_PROGRAM_POINT_SIZE);


    glGenVertexArrays(1, &m_VAO);
    glBindVertexArray(m_VAO);

    // the first VBO, it is the coordinates
    glGenBuffers(1, &m_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * sizeof(m_Points), &m_Points[0][0], GL_DYNAMIC_DRAW);

    // the second VBO, the color
    glGenBuffers(1, &m_VBO_Color);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_Color);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * sizeof(m_Colors), &m_Colors[0][0], GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(0);
    // in file axis.vs, there is a statement
    // layout (location = 0) in vec3 vertex;
    // the first argument 0 means (location = 0)
    glVertexAttribPointer(0,                 // location = 0 in vertics shader file
                          3,                 // the position has X,Y,Z 3 elements
                          GL_FLOAT,          // element type
                          GL_FALSE,          // do not normalize
                          sizeof(glm::vec3), // Stride
                          (void *) nullptr); // an offset of into the array, it is 0


    glEnableVertexAttribArray(1);
    // in file axis.vs, there is a statement
    // layout (location = 1) in vec3 vertex;
    // the first argument 1 means (location = 1)
    glVertexAttribPointer(1,                 // location = 1 in vertics shader file
                          3,                 // the position has R,G,B 3 elements
                          GL_FLOAT,          // element type
                          GL_FALSE,          // do not normalize
                          sizeof(glm::vec3), // Stride
                          (void *) nullptr); // an offset of into the array, it is 0


    glBindVertexArray(0);

Both the m_Points and m_Colors are some kind of std::vector<glm::vec3>

Here is my vertex shader and frame shader:

layout (location = 0) in vec3 vertex;
layout (location = 1) in vec3 color;

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

out vec3 ObjectColor;

void main()
{
    gl_Position = projection * view * model * vec4(vertex, 1.0);
    gl_PointSize = 10.0;
    ObjectColor = color;

}
#version 330 core

in vec3 ObjectColor;

out vec4 FragColor;

void main()
{
    FragColor = vec4(ObjectColor, 1.0f);
}

The draw code looks like below:

    shader.use();
    glBindVertexArray(m_VAO);
    glDrawArrays(GL_POINTS, 0, m_Points.size());

But I would like to add some points dynamically by AddPoint() function, so here is the code to add both vertex and color element in the vectors:

void AddPoint() 
{
    glm::vec3 p(5.0, 6.0, 0.0);    
    m_Points.push_back(p);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * m_Points.size(), &m_Points[0][0], GL_DYNAMIC_DRAW);

    glm::vec3 b(1.0, 0.0, 0.0);
    m_Colors.push_back(b);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_Color);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * m_Colors.size(), &m_Colors[0][0], GL_DYNAMIC_DRAW);
}

The problem is: the initial 4 points shows correctly with 4 different colors, but the AddPoint() never works, I don't see any new points added and rendered.

I know that if I put the vertex location in a single VBO,

such as:

The date array could be:

x, y, z, r, g, b
x, y, z, r, g, b
x, y, z, r, g, b
x, y, z, r, g, b

it works without any issue.

But why it does not work if I put the location and color in different VBOs?

Any ideas? Thanks.

This question(c++ - Storing different vertex attributes in different VBO's - Stack Overflow) is related, but I still don't know why my problem still happens.

EDIT Rabbid76 point out that glVertexAttribPointer() function only attach(copy) data from the previous bond VBO by glBindBuffer. Which suggest that I can't put the vertex location array and vertex color array in different VBOs?

EDIT2 Is my AddPoint() function wrong here?


Solution

  • glVertexAttribPointer associated the buffer object, which is bound to the GL_ARRAY_BUFFER target, to the specified attribute. The specification is stored in the state vector of the current Vertex Array Object.
    The proper buffer object has to be bound by glBindBuffer, before glVertexAttribPointer is invoked:

    // the first VBO, it is the coordinates
    glGenBuffers(1, &m_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * sizeof(m_Points), &m_Points[0][0], GL_DYNAMIC_DRAW);
    
    // the second VBO, the color
    glGenBuffers(1, &m_VBO_Color);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_Color);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * sizeof(m_Colors), &m_Colors[0][0], GL_DYNAMIC_DRAW);
    
    glEnableVertexAttribArray(0);
    
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO); // <--- bind `m_VBO`
    
    glVertexAttribPointer(0,                 // location = 0 in vertics shader file
                          3,                 // the position has X,Y,Z 3 elements
                          GL_FLOAT,          // element type
                          GL_FALSE,          // do not normalize
                          sizeof(glm::vec3), // Stride
    
    glEnableVertexAttribArray(1);
    
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_Color); // <--- bind `m_VBO_Color`
    
    glVertexAttribPointer(1,                 // location = 1 in vertics shader file
                          3,                 // the position has R,G,B 3 elements
                          GL_FLOAT,          // element type
                          GL_FALSE,          // do not normalize
                          sizeof(glm::vec3), // Stride
                          (void *) nullptr); // an offset of into the array, it is 0