Doom 3 md5mesh

I found some code recently on flipcode that loads the doom 3 md5mesh files and there seems to be a few things I don’t quite understand. I searched around but all I found is the math to animate a skin based off of the bones and weights which is not what I’m confused about. Ok in this md5mesh loading code it has a function called BuildVertices which some how computed the vertices of the mesh from the weights and bones. This is what I’m confused about. Before I say any more here is that code:

void BuildVertices(void)
{
for (int i = 0; i < g_NbMeshes; i++)
{
Mesh& mesh = g_Meshes[i];

  for (int j = 0; j < mesh.nb_vertices; j++)
  {
     Vertex& v = mesh.vertices[j];

     v.x = 0;
     v.y = 0;
     v.z = 0;

     for (int k = 0; k < v.weight_count; k++)
     {
        Weight& w = mesh.weights[v.weight_index + k];

        Bone& b = g_Bones[w.bone];

        v.x += (b.rot[0] * w.x + b.rot[3] * w.y + b.rot[6] * w.z + b.pos[0]) * w.t;
        v.z += (b.rot[1] * w.x + b.rot[4] * w.y + b.rot[7] * w.z + b.pos[1]) * w.t;
        v.y += (b.rot[2] * w.x + b.rot[5] * w.y + b.rot[8] * w.z + b.pos[2]) * w.t;
     }
  }

}
}

Its the last part where they compute the vertices from the bone’s rotations and the weights and whatever w.t is. I don’t seem to understand how the vertices are being computed like this. Could someone explain this to me or show me a paper that talkes about this? Like I say all I have found is papers talking about how to transform each vertex by the bones and weights in the vertex program, not anything about this.

Thanks.
-SirKnight

This code is simply doing the skinning in software.

b.rot/b.pos is the matrix for each bone. w.t is the weighting for that bone for the vert. w.x/y/z is the vertex location relative to each bone for the vertex. I suppose they redundantly store the position relative to each bone because you may actually be able to express things like twist differently from bend that way, assuming they re-calculate each time at runtime. Or maybe that’s just how their tool chain spits out the verts (which would be inefficient if that’s the only reason).

I don’t know if this is part of the renderloop, or just part of loading. If it’s part of loading, then they probably store the mesh in some arbitrary pose, and transform the mesh to some standard “identity” pose so they can share animations and run IK and stuff. If it’s part of the renderloop, then this is what actually skins the character (and needs a bit of optimization if you actually want to ship a game based on it :slight_smile:

A brief blurb about vertex weighting/skinning that I wrote on this forum a while back is found at http://www.mindcontrol.org/~hplus/vert_weighting.html

>>
v.x += (b.rot[0] * w.x + b.rot[3] * w.y + b.rot[6] * w.z + b.pos[0]) * w.t;
v.z += (b.rot[1] * w.x + b.rot[4] * w.y + b.rot[7] * w.z + b.pos[1]) * w.t;
v.y += (b.rot[2] * w.x + b.rot[5] * w.y + b.rot[8] * w.z + b.pos[2]) * w.t;<<

the first part is just a matrix33 plus position ie a 43matrix * a vertex
the w.t looks to be scaling that by a value ie a weight.
theres quite a few linear algebra tutorials on the internet (as well as in books) IIRC theres quite a good one at flipcode

I think this is the weight of that bone transform for the vertex in question. For a blend between multiple bones each vertex is transformed through both transforms of the connecting bone animations. In order to make the joints behave more smoothly the multiple transformed vertices are then multiplied by the weight that each bone contribution makes to the particular vertex (totals of all weights will be 1.0). Then the weighted vertex contributions are summed to produce the final vertex position.

Dobie and Zed,

I believe the confusing part is why there’s a separate x, y and z PER BONE per vertex. I took a stab at an explanation in my previous post – anyone care to guess (or educate) a little better?

The x y and z per bone is required post bone transform. Could it be that the pre transform may be in bone space (I notice you suggested this jwatte), or perhaps it’s simply a copy…? It really depends on what’s in the matrix, but it seems a bit redundant, perhaps it’s easier to not multiply all the bone xforms, and that goes back to how the animation is stored in the file and much earlier decisions about easy (or good looking) matrix lerping by Carmack I think. These have to end up in object space on the way out because they’re summed right there, but as for what’s going in and how the bone xform is constructed, we’re in the dark. It could also be inefficient demo coding, but I doubt that, someone who reverse engineered this would know what they were doing. Then again it may be that the demo coder broke the verts into bone space instead of chanied matrix transforms (or concatenations) as an arbitrary decision.

[This message has been edited by dorbie (edited 11-24-2002).]

Yes, it’s fairly clear each vertex is stored in bone local space for each bone. As far as I can tell, this only lets them avoid doing two translates when creating the bone matrices, which is about zero cost, while blowing out the size of the mesh by a noticeable factor.

Weerd. This has to be all for on-disk storage, as you couldn’t get a shader to skin with this particular data representation unless you totally bloated the DMA pipe. I notice most games don’t optimize for speed of download, but they DO optimize for speed of render :slight_smile:

Personally, I find it very simple and elegant to store everything in object local space and bake the bone-local-and-back transformations when calculating the pose (bone) matrices. Oh, well.

I think the mystery with the code up top is mostly solved now, though.

Do you have a link to the code on flipcode? I couldn’t find it, and google wasn’t playing

Thanks

Neil

Wow thanks for all the replies! I have never used any kind of models that had bones, wieghts and all that stuff before. I found it kind of wierd that they just didn’t store the mesh vertices then specify all the bone and weight stuff. But anyway, from looking at the model folders in doom 3, for each monster or whatever there is only one md5mesh file and there are a bunch of md5anim files. So I think this,

If it’s part of loading, then they probably store the mesh in some arbitrary pose, and transform the mesh to some standard “identity” pose so they can share animations and run IK and stuff.

is what they do.

Alright thanks, now time to figure out these md5anim files.

-SirKnight

Oh ya and about that link.
http://www.flipcode.com/cgi-bin/msg.cgi?showThread=00006455&forum=3dtheory&id=-1

The code is in there.

-SirKnight

theres quite a few linear algebra tutorials on the internet (as well as in books) IIRC theres quite a good one at flipcode

It’s not that I dont know linear algebra, it’s that I was confused on how they were computing each vertex for the mesh from only specifying the bones and wieghts. I didn’t know that you could analytically compute vertices from that. Guess so.

-SirKnight

Ok now that it’s been a few more hours since I last looked at all the replies today I’m more awake and I understand it much better now. I see after reading this again:
>> w.x/y/z is the vertex location relative to each bone for the vertex. << I see how the vertex positions for the ‘standard’ pose are computed.

-SirKnight

[This message has been edited by SirKnight (edited 11-25-2002).]