Looking for advice on a model format
I'm trying to write a nice binary mesh/model format, which I'll be able to read from a file quickly and easily. I have Assimp working, so I can import from other formats in order to save in my own, but I need some advice on how to organize everything.
One thing I want to avoid is a node/tree based file. I want everything in arrays, to make file reading as fast as possible. File I/O will likely end up being the main bottleneck in my game engine, so I want to make sure it's as fast as possible. If I'm wrong, and somehow node-based files are faster, please let me know.
So far I'm storing all of the vertices in a single packed array - No separate arrays for separate components, everything is together. My initial idea was then to have a single index array, and then use glDrawRangeElements in between each call (when I need to change materials, for instance), but I read that using glDrawRangeElements is quite a lot slower than simply glDrawElements, so I was considering putting each sub-mesh in it's own index buffer.
Question #1) Store sub-meshes together in a single index buffer, calling glDrawRangeElements, or in separate buffers, calling glDrawElements?
So far, for the vertex itself, I have 2 separate structures, each one a multiple of 32 bytes (I've read that it makes a big difference when transferring buffers to the gpu). The first, a minimalist vertex, contains 3 floats for it's position (x, y, z), 2 floats for texture coordinates (u, v), and 3 floats for the normal (x, y, z), a total of exactly 32 bytes. The second, which will probably be used most often for static geometry, contains everything in the first, plus 3 floats for a tangent (x, y, z), 3 floats for a bitangent (x, y, z), and then 8 bytes of padding, for a total of 64 bytes. The only advantage of the second over the first is that it supports tangent space normal mapping, and frankly, I don't enjoy having 8 bytes of padding. Is there something I could be using those 8 bytes for? Right now, it's wasted memory....
Question #2) Do the first 2 vertex formats look good? What could I use those 8 extra bytes for?
Next, I need to be able to support the following features:
- Transform animations (rotation, translation, and scale of an entire sub-mesh over a period of time)
- Skinning (hardware skeletal animation, with animations in separate files)
- Morph targets (both as an animation on it's own, and to be used alongside skeletal animation)
And, frankly, I have no idea how to implement any of those features, but I want to prepare my model files to be able to support it.
For transformation animation, the best idea I can think of is to store a "timeline" along with each sub-mesh. The timeline would be an array where each element is a keyframe containing a matrix and a time, and the game would interpolate between one matrix and the next based on the current time.
As for skinning... Frankly, I'm not sure where to start. I've done some Google searching, but most of the information I've found has been scattered and/or incomplete. Can somebody share a link to a comprehensive skinning tutorial in GLSL? I want to do it in the vertex shader, but I want to maintain compatibility with OpenGL 2.0 and 2.1, so I'd rather not use integer attributes (which are only available in GL 3+).
For morphing... My best guess is to store each morph target as it's own vertex buffer, and then send multiple vertices to the vertex shader, which will interpolate between them. How can I do that? I can't bind two vertex buffers at once, can I?
Any advice that you could share would be much appreciated!