glDrawElementsInstanced with subsets/offsets of larger data sets?

Started by
0 comments, last by Matias Goldberg 9 years, 6 months ago

This is probably a silly question, but I've managed to get myself turned around and I'm second guessing my understanding of instancing.

I want to implement a label renderer using instanced billboards. I have a VBO of 'label positions', as 2D vertices, one per label. My 'single character billboard' is what I want to instance, and is in its own VBO. Due to engine/architectural reasons, I have an index buffer for the billboard, even though it is not saving me much in terms of vertex counts.

For a various reasons I still want to loop through individual labels for my render, but planned to call glDrawElementsInstanced, specifying my 'billboard model', along with the character count for a label. However, I can't see how I can tell glDrawElementsInstanced where to start in the other attribute array VBO's for a given label? So, if I am storing a VBO of texture coords for my font, per-character, how do I get glDrawElementsInstanced to start at the first texture coord set of the first character of the current label being rendered?

I see that glDrawElementsInstancedBaseVertex exists, but I'm getting confused about what the base vertex value will do here. If my raw/instanced billboard verticies are from index 0..3 in their VBO, but the 'unique' attributes of the current label start at element 50 in their VBO, what does a base vertex of 50 do? I was under the impression that it would just cause GL to try to load billboard vertices from index+basevertex in that VBO, which is not what I want.

I guess to sum my question up, if I have an instanced rendering implementation, with various attribute divisors for different vertex attributes, how can I initiate an instanced render of the base model, but with vertex attributes starting from offsets into the associated VBO's, while abiding by attribute divisors that have been set up?

EDIT: I should mention, I've bound all the related VBO's under a Vertex Array Object. By default I wanted all labels to be sharing VBO memory to avoid state changes, etc. It seems like there must be a way to render just N instances of my model starting at some mid-point of my vertex attrib arrays.

Advertisement

I don't understand what you want to do.

glDrawElementsInstanced can only render primitive N times. So if you've got a tree, you can render 10 trees with the same draw call.
Per-tree parameters (so that not all 10 trees get rendered exactly the same on the same place) can be obtained either using the special GLSL variable "gl_InstanceID" or using attribute divisors (so that i.e. tree's position is loaded at a rate of one per tree i.e. 10 times, instead of 10 * number_of_vertices times).

If you want to do something else than that, you either get very creative with gl_InstanceID and attribute divisors, or use another function (or change the approach entirely).


glDrawElementsInstancedBaseVertex is almost the same, the difference is that thanks to its "basevertex" parameter, you can render a tree and a car without changing VAOs or rebinding VBOs while still using 16-bit indices, provided that you stored the car's vertex data right after the tree in the same vertex buffer. "basevertex" is effectively an offset (i.e. 'start reading from this place')

Again, if you want do something else than that, you have to get very creative with gl_InstanceID, attrib. divisors, or basevertex.


Now, I get the feeling that what you want is to have 4 vertices per billboard; and ~128 sets of 4 UVs (i.e. 4 per ASCII glyph). Then magically for every 4 vertices, load the UVs to select the right glyph for each billboard.

  • One way to do it is to set the attribute divisor to 1 and in that attribute send the glyph ID, which you will use to load the UVs from an UBO or TBO. Use "ubo[glyphID + gl_VertexID * 4]" to calculate which one of the UVs to use.
  • Another way (without attribute divisor) is to send the glyph ID in an UBO, and use gl_InstanceID to get the glyph from it (i.e. glyphID = uboGlyphs[gl_InstanceID]); then do the same as in the other case (load the UVs from another UBO, use ubo[glyphID + gl_VertexID * 4])
  • Another way to do it is to fill the UBO with the 4 UVs per glyph every frame and then use ubo[gl_InstanceID * 4 + gl_VertexID] to load the UV for the specific vertex.

All three are very similar, they just vary in trade offs: how many indirections there are gpu-side vs how much data is sent to the gpu every frame.

This topic is closed to new replies.

Advertisement