javascriptvertex-bufferwebgl2vertex-array-object

When drawing multiple objects, when do you create a new vertex array object?


I'm trying to create a game with WebGL.

I currently have three textures, one with letters for the font, a sprite sheet for the character, and a tilemap for the world. So I have a few large textures and I need to draw a small part of them multiple times.

What is the best way to do this?

My current approach is to use a VAO for each letter, square on the map, character pose, etc... so I would have 150+ VAO's. I thought VAO's were good because they were simple and fast, but this, this, and others makes it seem like this isn't the best option.

The other approach I know of would be to only have three VAO's and change the location where WebGL starts reading in the buffer to get the location of the right letter, for example. So instead of hundreds of VAO's with tiny arrays, I would have three VAO's with large arrays. If this is the right approach, would I have to call gl.vertexAttribPointer() after gl.enablevertexAttribArray() every time I draw something, or do I just modify the count parameter in gl.drawArrays() ?

gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ) is 16 or 32, so chopping up the textures doesn't seem like a good method either.

What is the best conceptual approach?


Solution

  • How many VAOs is up to you. There are many tradeoffs. As far as text goes though the most common way is to text is to put your glyphs in a texture atlas, and generate a buffer with the vertices for all the letters you want to draw.

    In other words.

    each frame
       for each string
          for each letter in string
             add vertices for letter to buffer
    
    drawArray/drawElements(gl.TRIANGLES, ... totalOfAllLettersInAllStrings * 6);
    

    So there is potentially only a single draw call for all letters (like for a UI). There is not one per letter. That would be way to slow.

    Here's an article on it

    Your comment on MAX_TEXTURE_IMAGE_UNITS also sounds like maybe there is a mis-understanding? Texture Units are just the maximum number of textures a shader can reference in a single draw call. They are not the maximum number of textures period. You can have 1000s of textures. You can just only reference a certain number for them with each draw call.

    As far as drawing text, you generally only need a single texture per font style for simple cases. Though it can get complicated fast if you want to support all of unicode instead of say just ASCII.