3
\$\begingroup\$

I've run into the situation where the size of my mesh with all its vertices and indices, is larger than the (optimal) vertex buffer object upper limit (~8MB). I was wondering if I can sub-divide the mesh across multiple vertex buffers, and somehow retain validity of the indices. Ie a triangle with a indice at the first vertex, and an indice at the last (ie in seperate VBOs).

All the while maintaining this within Vertex Array Objects. My thoughts are, save myself the hassle, and for meshes (messes :P) such as this, just use the necessary size (> 8MB); which is what I do at the moment. But ideally my buffer manager (wip) at the moment is using optimal sizes; I may just have to make a special case then...

Any ideas? If necessary, a simple C++ code example is appreciated.

Note: I have also cross-posted this on stackoverflow, as I was not sure as to which it would be more suitable (its partly a design question).

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Any reason why you don't just split the object into several? If some primitives need data from two buffers, just duplicate those (relatively rare) bits of data.. \$\endgroup\$ Commented Feb 21, 2011 at 7:42
  • \$\begingroup\$ This may be the answer I have to go for, but a slightly different version; which involves splitting the model itself into separate meshes. No chance of shared indices across the meshes. Yet allowing for that special case also. \$\endgroup\$ Commented Feb 21, 2011 at 9:17

3 Answers 3

4
\$\begingroup\$

To quote the best answer given on StackOverflow by datenwolf.

8MB of vertex data is quite a lot for a single model. I'm pretty sure this model could be split into individual meshes. Good places for splitting a mesh are sharp edges, since vertices along these edges have different normal vectors are thus not identical and cannot be shared.

However more important than the VBO size is the size of the render batch passed to glDrawElements (or glDrawArrays). In my experience the optimal size for render batches are between 100 to 2000 triangles, before cache pressure kicks in. But you should measure that on your system yourself.

In most OpenGL applications each distinct "object" visible has some between 100 to 3000 vertices. Complex models are broken down into parts. E.g. it makes little sense to send a complex character model as whole, since that would require all the skeletal and facial animation shaders to be processed on the whole mesh. At least in the games I contributed we've split characters into each leg, each arm and hands. The head portion is split into neck and back of the head; the whole facial area is a complete own mesh, but does not contain the eyes, jaw and tounge, those are animated separately

\$\endgroup\$
1
\$\begingroup\$

There are a couple of ways to reduce data. First see if you can drop from float to some other format. Can you use 16bit integers for position and store a scale per mesh? Can you compress normals? Two floats might work, or two integers, or use a format like GL_INT_2_10_10_10_REV. Compress other vertex data in similar fashion.

How do you render your data? Triangles? Try using triangle strips and reuse vertex data as much as possible. Use primitive restart if you cannot render your whole mesh in one strip. Use something like NVidia Mesh Tools to generate this data.

At least something to start with. =)

\$\endgroup\$
3
  • \$\begingroup\$ Interesting concepts, how would using shorts for position (assumed vertex positions) work? If you could give an example on how to set that up. Only post what would be different in comparison to a traditional setup. Triangle strips require pre-formatting all your data, which I don't want entirely necessary? \$\endgroup\$ Commented Mar 14, 2011 at 7:42
  • \$\begingroup\$ For the position, figure out your maximum absolute x, y, z values (loop over all your positions and do something like mx = max(mx, abs(vertex.x))). Then divide all your positions with this value and multiply with MAX_INT16 (or similar). You can now convert to a short, just be careful of rounding errors since this will quantize your positions. Just multiply with your scale (mx, my, mz) in the vertex program to convert back to unscaled space. And yeah, preprocessing is required for strips, but it can be done right where you create your geometry too (I do that for splines and tubes.) \$\endgroup\$
    – void
    Commented Mar 14, 2011 at 8:52
  • \$\begingroup\$ Go with triangle strips all the way, with restarts or with degenerate triangles. Another tool for generating strips is cs.sunysb.edu/~stripe \$\endgroup\$
    – Will
    Commented Mar 14, 2011 at 9:03
0
\$\begingroup\$

What you could do is divide the different inputs into different buffers- e.g., a buffer for posiiton, a buffer for normal, etc. This is similar to how Direct3D (don't know about OGL) achieves hardware instancing- they have a buffer for static data, and a buffer for per-instance data.

\$\endgroup\$
1
  • \$\begingroup\$ That would surely throw the cache around? Isn't the intention to interleave your data as much as possible? In any case, at this time I am simply loading vertices, the texture data etc in this case would bloat the model to beyond 8MB. Which is why I want to find a solution now. \$\endgroup\$ Commented Feb 21, 2011 at 23:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .