Looking for a more flexible way to use VBO's

I am looking to store my vertex data into a VBO, but I am wondering what the best approach would be. Originally I created a vertex format that was interlaced.

struct InterlacedVertex
{
vec3f pos;
vec3f normal, tan, binormal;
vec2f texcoord;
byte color[4];
};

VBO Memory Layout:
N = number of verts
[pos, normal, tangent, binormal, texcoord, color] * N

Most values were passed as attribute arrays with small VBO offsets into the vertex format. This worked okay, but it was pretty limiting. I couldn’t use more than 1 set of texture coordinates, and my (CPU) animation code was forced to upload the entire vertex array since there was no easy way to only update a subset (position and tangents only, leaving color and uv untouched). Even if I found a way to add more texture sets, it only meant more unchanged data would be wastefully uploaded each frame.

Now I am thinking about creating separate arrays for each component, but this seems like it would be a cache nightmare.

VBO Memory Layout:
N = number of verts
M = number of uv sets
[N points][N normals][N tangents][N colors][N*M texcoords]

* CON - for each vertex, the driver will have to sample across huge spans of memory...
* PRO - can update subsets of the model without having to re-upload unchanged data.
* PRO - can support multiple texture coordinates, now that it is not interlaced.

Suggestions? Has anyone tried both and seen a difference?

Discard notions of “normal, tan, binormal, texcoord, color” as something always-present, if you want flexibility. Make per-material code to transcode and pack in whatever format. Have string-like descriptors of vertex-attribs (a tuple if AttribID and attribDataType), have a function read those descriptors and call glVertexAttribPointer() with the appropriate params, while calculating offsets and vtx-size. You can call this function twice, with different descriptors to bind two VBOs.

It sounds like too much work and code, but actually isn’t.