Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 5 of 5

Thread: Binding Multiple VBOs and EBOs to VAO?

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2018
    Posts
    5

    Question Binding Multiple VBOs and EBOs to VAO?

    Hi thanks for clicking into my post first. I am recently learning OpenGL from scratch (Just finish the multiple boxes tutorial in learnopengl.com).


    The tutorial is easy to understand. But when it comes to real scenario, things are becoming different. It only shows how one VBO binding to one VAO. In theory, VAO is just the way organizing similar VBOs together (same attributes and shaders). Now suppose I have 10k houses with different locations and shape, but they share the same shaders and attributes. Obviously, I could allocate 10k VAOs and 10k VBOs and 10k 10k EBOs to make 10k drawCalls to accomplish this. However, everyone would punch on my face in the forum if I did that I believe. Instead, I want to put these 10k VBOs & EBOs inside one VAO. However, I don't know what is going wrong but it simply doesn't render anything. (or I set camera in the wrong position?)

    TL;DR
    More details: I read data from disk dynamically and assigning them to "std::vector<std::vector<Vertex>> houses, there Vertex is just a simple class that represents the vertex (sizeof(Vertex) = 32, including 8 floats of data to represent position, color & textureCoord, honestly I wonder thy it's only 32 bytes, coz the data itself has 4*8 bytes already, and a class should have some overhead. but it is continuous block of memory so I think it is fine). Now the code to bind my data is like this:
    Code :
    std::vector<std::vector<Vertex>> houses
    std::vector<std::vector<unsigned int>> housesIndices
    GLuint *VBOs;
    GLuint *EBOs;
    GLuint VAO;
    GLShader shader;
    unsigned int totalIndices = 0;
     
    glGenVertexArrays(1, &VAO);
    shader = GLShader("myshader.vs", "myshader.fs"); // I used the Shader class at learnopengl.com
     
    VBOs = new GLuint[houses.size()];
    EBOs = new GLuint[houses.size()];
    glBindVertexArray(VAO);
    for(size_t i = 0; i < houses.size(); ++i){
      glGenBuffers(1, &VBOs[i]);
      glBindBuffer(GL_ARRAY_BUFFER, VBOs[i]);
      glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*houses[i].size(), &houses[i][0], GL_STATIC_DRAW);
     
      glGenBuffers(1, &EBOs[i]);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[i]);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*housesIndices[i].size(), &housesIndices[i][0], GL_STATIC_DRAW);
     
      totalIndices += housesIndices[i].size();
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
      glEnableVertexAttribArray(0);
     
      // this is to aoivd if I accidentally set my vertex in clockwise order
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      glBindVertexArray(0);
    }
     
    // in rendering loop:
    shader.use();
    glm::mat4 model = glm::mat4(1.0f);
    shader.setMat4("model", model);
     
    // xmin is the min value of vertices in these houses, same for xmax, ymin, ymax
    // I just wanna have a top down view of these houses, the z value is guaranteed to be small, around 0
    // camera_dir is (0, 0, -1.0f) camera_up_ is(0, 1.0f, 0)
    camera_pos_ = glm::vec3((xmin+xmax)/2, (ymin+ymax)/2, 50.0f);
    view = glm::lookAt(camera_pos_, camera_pos_ + camera_dir_, camera_up_);
    shader.setMax4("view", view);
     
    // projection
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
    shader.setMat4("projection", projection);
     
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, totalIndices, GL_UNSIGNED_INT, 0);

    The shader I use is just having "aPos" as one attribute and three uniform mat4 representing MVP matix. In fragshader itonly outputs red color

    Is it the correct way to bind VBOs, EBOs & VAO? Please correct me if I did something wrong in my code.

    Note: Qt5.6, (I set OpenGL version to 3.3 in Qt format), Ubuntu 16.04, C++14
    Last edited by sylorr; 07-13-2018 at 10:00 AM.

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,962
    A VAO holds all of the state associated with each attribute array (enabled, buffer, offset, stride, format, divisor), and also the element (index) buffer.

    If you have multiple "objects" which all have the same shaders and thus use the same attributes, the sensible approach is to store all of the attributes and indices in a single set of buffers (one element buffer and at most one buffer per attribute), so you can draw all of the objects with a single glDrawElements() call, or arbitrary subsets using multiple glDrawElements() calls each using a subrange of the element array or a single glMultiDrawElements() call. All of that state can go in a single VAO.

    If each object has its own set of buffers, then it also needs its own VAO, and will need a separate draw call.

  3. #3
    Junior Member Newbie
    Join Date
    Jul 2018
    Posts
    5
    Quote Originally Posted by GClements View Post
    A VAO holds all of the state associated with each attribute array (enabled, buffer, offset, stride, format, divisor), and also the element (index) buffer.

    If you have multiple "objects" which all have the same shaders and thus use the same attributes, the sensible approach is to store all of the attributes and indices in a single set of buffers (one element buffer and at most one buffer per attribute), so you can draw all of the objects with a single glDrawElements() call, or arbitrary subsets using multiple glDrawElements() calls each using a subrange of the element array or a single glMultiDrawElements() call. All of that state can go in a single VAO.

    If each object has its own set of buffers, then it also needs its own VAO, and will need a separate draw call.
    Thanks, I may try to make my std::vector<std::vector<Vertex>> to a continuous block or array. But I still have another question that in my case, why it cannot render anything? In other word, when I bind a new VBO via glBindBuffer() and bind data via glBufferData(), would it override previous VBO in GL_ARRAY_BUFFER? Or it simply attaches behind previous bound data.

  4. #4
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,962
    Quote Originally Posted by sylorr View Post
    But I still have another question that in my case, why it cannot render anything? In other word, when I bind a new VBO via glBindBuffer() and bind data via glBufferData(), would it override previous VBO in GL_ARRAY_BUFFER? Or it simply attaches behind previous bound data.
    Each glVertexAttribPointer() call is overwriting the state from the previous call, so you end up with the VAO containing the state from the last such call. Similarly for the glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) calls.

  5. #5
    Junior Member Newbie
    Join Date
    Jul 2018
    Posts
    5
    Quote Originally Posted by GClements View Post
    Each glVertexAttribPointer() call is overwriting the state from the previous call, so you end up with the VAO containing the state from the last such call. Similarly for the glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) calls.
    Thank you! That's the most valuable point I have learned for the whole week.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •