Firstly, this is my first post on this forum so Hi All.
Secondly, I am new to opengl so please take this into consideration.
Now my question.
I would like to put mutiple indexed meshes into single VBO but the problem is - what to do with indices. Each mesh has it’s own indices but when all the meshes will be contained in a single buffer then the indices needs to be shifted by some offset. In DirectX I just used DrawIndexedPrimitive with proper settings ( providing index offset, which was added to all indices ).
Is there a way to provide opengl with index offset or do I have to recalculate indices manually after adding mesh to VBO or maybe I just don’t now something?
One more thing - I need to do this in gles2.
Thanks in advance
When setting up your vertex attribs with glVertexAttribPointer you pass the offset (in bytes!) into the buffer as the last parameter, see this tutorial for a similar example.
The tutorial stores different attributes (position and color) of one mesh in the same buffer, but the method is the same.
Also, you can use glDrawElementsBaseVertex, in order to avoid moving the attribute offsets around.
I’ve been wondering the same thing too, whether it’s faster to set all the gl***Pointer functions before drawing with each mesh:
gl***Pointer(..., mesh[i].offset + mesh[i].attribute[j].offset); // for each attribute
gl***Pointer(..., mesh[i].offset + mesh[i].attribute[j].offset);// for each attribute
or whether it’d be better to adjust the indices as meshes are placed into a buffer object, getting rid of the need for gl***Pointer calls:
gl***Pointer(..., 0); // for each attribute
If you are prepared to limit to OpenGL 3.2+ (or GL_ARB_draw_elements_base_vertex), then you can provide a base vertex that is added to all the indices:
glDrawElementsBaseVertex(GL_TRIANGLES, 39, GL_UNSIGNED_SHORT, NULL, mesh[i].basevertex); // other ***BaseVertex functions exist
Without GL_ARB_draw_elements_base_vertex, then I think if you were to use unsigned short indices, you would be limited to 65536 vertices per buffer object, which isn’t as bad as it sounds if you have 32 bytes per interleaved vertex, that’s a 2 MB buffer object. But if you aren’t using interleaved vertex data, then you’d might up with several smaller buffer objects, eg. from 128kb to 1MB.
Another few related questions I have, are:
- How much do OpenGL implementations gain from using glDrawRangeElements instead of glDrawElements too? It says that if the range is small enough, it could automatically convert indices to a smaller data type (eg. from GL_UNSIGNED_INT to GL_UNSIGNED_SHORT), but would it do this on every draw call?
- If you have meshes that needs certain data updated every frame, such as vertex position + normals, and you want to group several meshes into a single buffer object, how + when is the best way to update this data without causing slowdown?
- Do vertices or indices gain anything from being aligned to certain values, or if they were in the same buffer object, could they be tightly packed?
glDrawRangeElements is just a hint; OpenGL implementations are completely free to use the info you provide or ignore it if they wish. I can’t see how an implementation could possibly convert an index format from a larger size to a smaller size without incurring some overhead, and then we’re in tradeoff land. Is the cost of that overhead acceptable compared to the gain from using the smaller size?
For updating I’d typically use two VBOs - a static for the attributes that are not updated and a dynamic for those that are. Your mileage may vary, and I’d expect that it would need tuning for your chosen target hardware.
I’ve personally never seen any gain from aligning vertexes to 32, 64 or whatever bytes. I don’t believe that it’s an absolute “do this and your program will be faster” rule. It may be faster under certain circumstances for sure, I’ll accept that, but again it’s a case of test, tune, make a decision.
whether it’d be better to adjust the indices as meshes are placed into a buffer object, getting rid of the need for gl***Pointer calls:
This is generally going to be faster. Minimizing the number of gl*Pointer calls is a good idea, even if the calls don’t actually change buffer objects.
How much do OpenGL implementations gain from using glDrawRangeElements instead of glDrawElements too? It says that if the range is small enough, it could automatically convert indices to a smaller data type (eg. from GL_UNSIGNED_INT to GL_UNSIGNED_SHORT), but would it do this on every draw call?
That’s not really what it’s for nowadays. To the extent that glDrawRangeElements is helpful these days, it’s primarily about telling the implementation how much of the buffer object you’re actually using in this draw call.
Do vertices or indices gain anything from being aligned to certain values, or if they were in the same buffer object, could they be tightly packed?
It depends on the hardware. The general rule of thumb (taken with a grain of salt) is this:
Every individual attribute regardless of size should start on 4-byte alignment. That means if you have your positions as 3 shorts or half-floats, then you can’t really use that extra 2 bytes for anything.
Yes I know about that one but as I have said in my OP I need to do this in gles2 and that’s OpenGL 2.0 and glDrawElementsBaseVertex is supported in >= 3.2 only and I cannot base on extensions.
One other thing though. Would it be better to recalculate indices when mesh is transfered to vbo and then if I am using many meshes with same attrib layout I could limit attrib pointer setting calls.
In other words lets say that I have 1000 meshes with the same attrib layout ( glVertexAttribPointer calls would be identical in terms of parameters for each mesh )
1.1 copy meshes to vbo’s
1.2 recalculate (offset) indices according to mesh placement in vbo
2.1 glVertexAttribPointer once
2.2 draw all meshes
– OR –
1.1 copy meshes to vbo’s
2.1 glVertexAttribPointer for mesh
2.2 draw mesh
2.3 goto 2.1 and repeat for every mesh