Skeletal Animation Using Half-Life 2 MDL (SMD)

Started by
4 comments, last by slang 18 years, 2 months ago
Over the past few weeks, I have attempted to implement Skeletal Animation using the Half-Life 2 MDL (converted to SMD) file format, but I am suffering from some buggy behaviors. As you can see in the screenshots above, at this point right now, I can correctly render SMD reference models (and construct bone hierarchies, also). However, what I am suffering is this: http://www.quake4.jp/slang/files/videos/flx_hl2_mdl_01.m1v The model in the video is CPU-skinned and I am also implementing GPU skinning simultaneously, but the buggy behaviors are the same in both cases (I am using OpenGL and GLSL, by the way). Hence I suspect that the bone transformations are the problem, maybe relating to DirectX's left-handed coordinate system and OpenGL's right-handed coordinate system, but I am at a loss what I should do. Any ideas?
Advertisement
Handedness could be the problem, in which case you want to invert all the Z components of the positions and normals. Rotations should be fine since all you're doing is reconciling the difference in axial handedness.

If that doesn't work, then you might try checking out the HL2 SDK (c_baseanimating.h/cpp in particular) or the Source WiKi. Unfortunately I can't tell you more because I've never worked that closely with any generation of the MDL format.
Zipster:

Thanks for your reply.

Well, I had already tried inverting all the Z components of the reference model before, but it didn't work. As you said, I'm gonna check the Half-Life 2 SDK for the source code.

---

Let v denote the vertex position in the reference model space, and let M denote the bone-to-world transformation matrix, then the skinned vertex position v' is given by:



As previously noted, I can correctly calculate the v' in case of reference postures at this point. However, the problem occurs when it comes to animations. So, I am narrowing down the cause of the problem into the bone-to-world transformation matrix M of the animation keyframes.

And I have figured out that the bones used for animations are rotated 90 degrees around Y axis of the reference model space. It's really strange and I think the problem may be related to that.

[Edited by - slang on January 29, 2006 6:14:47 AM]
All I've had to work from is this somewhat incomplete reference on the file format. I found a few files in the studiomdl project with the SDK (studiomdl.cpp, bone_setup.cpp) but they were a mess. How are you calculating the vertex position in reference space, or in other words how do you build Mref? In the triangle data I see that each vertex has a world position plus a series of bone weights, which indicates to me that if you can determine the position of a vertex as a function of the weighted bone transformations then you can animate everything properly. However I don't have any working code to play with, so I can't be certain.
> How are you calculating the vertex position in reference space,
> or in other words how do you build Mref?

There are mainly two types of the Half-Life 2 SMD file format; one is Reference SMD, and the other is Animation SMD.

In the Reference SMD, as you already noticed, each vertex has its own position in world space (I used "reference space" for this) and there also exists reference bone data (positions and rotations).

Since all the bone data defined in the Reference SMD is given by in their parents' local spaces, first I transform all of the bones' local transformation matrices into the bone-to-world transformation matrices (these will be Mref in the equation, I think). Then I calculate the inverse of Mref in order to transform the vertex from the reference space into the parent's local space, because the bone transformation matrix Mi of the animation is also bone-to-world.

The strange thing is, like I said, the bone data defined in the Animation SMD is 90-degree-rotated around Y axis of the reference space. I almost believe this causes the problem but, more strangely, I have found that not all of the bones are rotated. Some are, but some aren't...

> if you can determine the position of a vertex as a function of the
> weighted bone transformations then you can animate everything properly.

What exactly do you mean "as a function"?

Thanks again.
I think I am one step closer to the success of the implementation, but still I have the buggy behaviors...



I updated the video (7.32 MB).
http://www.quake4.jp/slang/files/videos/flx_hl2_mdl_01.m1v

And here goes part of the source code.

void FLXbone::CalculateLocalTransformation(void){   glPushMatrix();   {      glMatrixMode(GL_MODELVIEW_MATRIX);      glLoadIdentity();		      // bone's local translation and Euler rotations      glTranslatef(m_Position.x, m_Position.y, m_Position.z);      glRotatef(RADTODEG(m_Rotation.z), 0, 0, 1);      glRotatef(RADTODEG(m_Rotation.y), 0, 1, 0);      glRotatef(RADTODEG(m_Rotation.x), 1, 0, 0);		      glGetFloatv(GL_MODELVIEW_MATRIX, m_Transformation.m);   }   glPopMatrix();}


// transform all of the bone transformation matrices into world spacefor (i=0; i<m_NumBones; i++){   int parent_id = m_Bones.m_ParentID;			   mat4 transformation = m_Bones.m_Transformation;   while (parent_id != -1)   {      transformation = m_Bones[parent_id].m_Transformation * transformation;      parent_id = m_Bones[parent_id].m_ParentID;   }			   m_TempBones.m_Transformation = transformation;}   // calculate the inverse of the bone's transformation matrixfor (i=0; i<m_NumBones; i++){   m_Bones.m_Transformation = m_TempBones.m_Transformation;   m_Bones.m_Inverse = m_Bones.m_Transformation;   // use quarternion inverse		   quat inverse_tm(m_Bones.m_Inverse.m);   inverse_tm.Invert();   inverse_tm.GetMatrix(m_Bones.m_Inverse.m);}


Any help, comment or indication would be appreciated!!!

Thanks.

This topic is closed to new replies.

Advertisement