2

I was just trying to learn how VBOs and IBOs work in WEBGL. Here is my understanding: IBOs help reduce the amount of info passed down to the GPU . So we have a VBO and then we create an IBO with its indices pointing to the VBO. I had a doubt as to how WEBGL knows the IBO <--> VBO mapping . In case of a single VBO/IBO , I thought as GL was a state machine it sees the last ARRAY_BUFFER it is bound to and then uses that buffer as the IBO target .Below is a case with multiple VBOs(position buffer and color buffer) as given below:

    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, cubeVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    setMatrixUniforms();
    gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

In the above code(which works - i took it from a tutorial), we have two VBOs and one IBO (cubeVertexIndexBuffer) , what i don't understand is how WEBGL knows the indices of the IBO point to the position buffer and not the color buffer(though the color buffer is the last bound ARRAY_BUFFER).

Please let me know as to what I am missing here....

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
user108788
  • 23
  • 4

2 Answers2

4

The GL_ELEMENT_ARRAY_BUFFER binding has nothing to do with the GL_ARRAY_BUFFER binding, each binding is used by a different set of commands. This is why people should not learn OpenGL using multiple VBOs in the beginning, interleaved VBOs avoid this sort of confusion. I will attempt to clear up your confusion below.

The GL_ARRAY_BUFFER binding is used for commands like glVertexAttribPointer (...). The GL_ELEMENT_ARRAY_BUFFER binding, on the other hand, by glDrawElements (...).

The indices in the IBO point to neither of the element arrays per-se. What they point to are the glVertexAttribPointer (...)s you setup while you had a GL_ARRAY_BUFFER bound.


In case it was not already obvious, you cannot have more than one buffer object of the same type bound at any given time. When you set your attrib pointers and you are not using interleaved arrays you have to change the bound VBO. Thus, glDrawElements (...) could not care less which VBO is bound, it only cares about the vertex attrib pointers that you setup and the bound element array. Those pointers are relative to whatever VBO was bound when you set them up, but after the pointer is setup the state of the binding is no longer relevant.
Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • Hi Andon, Thanks for the reply ....but I am still not getting this Ok let me try to put it this way , currently in the above code , the indices are being linked to the position buffer thru gl.vertexAttribPointer ...how do I change it so that the indices refer to the color buffer... – user108788 Dec 03 '13 at 07:58
  • @user108788: No they're not. I do not know how to make this any clearer. The element array buffer has **nothing** to do with your individual VBOs. The element array buffer actually provides an array of indices into the **POINTERS** that you setup with calls to `glVertexAttribPointer (...)`. In other words, the only command that has anything to do with which VBO is bound is `glVertexAttribPointer (...)` after that command completes you can pretend like your vertex data comes from a single location on the GPU and forget about the individual VBOs that were used to create the pointers. – Andon M. Coleman Dec 03 '13 at 08:21
  • @user108788: Again, this is why I don't suggest people start learning OpenGL using multiple VBOs instead of interleaved arrays. It can be confusing. Suffice it to say, the element array buffer pulls vertex attribute N from each set of attributes when you draw using `glDrawElements (...)` when it encounters the index N. The element array buffer does **NOT** index a single vertex buffer, it uses the same index from each of the attrib. pointers to pull each vertex attribute needed for renering. – Andon M. Coleman Dec 03 '13 at 08:23
  • Hi Andon..that cleared it up for me....thanks a lot!! i sort of realised how totally out of track i was...any good links/books you recommend for newbies like me... – user108788 Dec 03 '13 at 09:35
  • @user108788: http://www.arcsynthesis.org/gltut/ has an excellent series of tutorials for desktop OpenGL. It is a little theory heavy, but honestly that is a good thing. If you can stomach learning more theory than actual coding in the beginning you will be much better off in the long-run. It applies to desktop GLSL, however, which has a different syntax from OpenGL ES 2.0 / WebGL (they use something close to desktop GLSL version 1.2). I am not familiar with any WebGL or ES 2.0-specific tutorials unfortunately - I know they exist, I just could not recommend any :-\ – Andon M. Coleman Dec 03 '13 at 10:11
  • Thanks once again Andon! – user108788 Dec 03 '13 at 19:24
1

The statefulness in OpenGL is awful. If you want to work with any of the buffers, you almost always need two calls: One to tell OpenGL which buffer you want to use and a second (and third and more) that operate on the buffer. The ambiguous buffer names make the whole thing more confusing. So, let us quickly clear up some things:

  1. As explained here, binding to gl.ARRAY_BUFFER (or GL_ARRAY_BUFFER) indicates that the specified buffer is a VBO.
  2. gl.ELEMENT_ARRAY_BUFFER (or GL_ELEMENT_ARRAY_BUFFER) indicates an IBO (that link is worth checking out). An IBO represents one complete surface. It is a list of indices to all vertices that this surface is made of. The IBO needs to be bound to gl.ELEMENT_ARRAY_BUFFER before a draw call because that's how the pipeline knows which vertices are where.
  3. Since you sometimes need multiple attributes per vertex that you might (for some reason) want to store in separate buffers, you can use a single IBO to index into multiple VBOs.
  4. Finally, (and I think, here is your confusion), the vertexAttribPointer tells the shader to look up the given attribute of given type in the given relative offset in the VBO that is bound when vertexAttribPointer is called. This way, the pipeline can get each attribute once it has the right vertex index, which it reads from the IBO. In your case, vertexAttribPointer says that the vertexPositionAttribute comes from the cubeVertexPositionBuffer, and color from your color buffer. In order to avoid calling vertexAttribPointer before every draw call, you can instead use a VAO to cache that information.
Community
  • 1
  • 1
Domi
  • 22,151
  • 15
  • 92
  • 122
  • I wouldn't go as far as to say that the shader looks up up the attribute from the currently bound VBO. By the time the shader gets around to running, the currently bound VBO is irrelevant. The only thing that the VBO binding was relevant for was the call to `glVertexAttribPointer (...)`. – Andon M. Coleman Dec 03 '13 at 06:09
  • @AndonM.Coleman I don't think that "vertexAttribPointer tells the shader to look up the given attribute of given type in the currently bound VBO" means "the buffer that is bound at the time the shader is running", but let me change the wording nevertheless. – Domi Dec 03 '13 at 06:55