Jump to content
  • Advertisement
Sign in to follow this  
Ging

MD5 animation issues

This topic is 4379 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm writing up an md5 viewer as part of some uni work, but I've got some issues with my animation. I've gotten most of the info I need from doom3world and a couple of related sites. This shows the issue I'm having, the left image is the base pose from the md5mesh file, the middle is the baseframe from the md5anim and the right image is frame 0. As you can see, the baseframe is slightly out of whack - the rest of the frames are completely gone however. I've included the code I'm using to move from relative to absolute vertex values. I suspect the issue is in there somewhere, but I can't figure it out at the moment!
		for ( int j = 0; j < m_iBoneCount; j++ )
		{
			Bone &bone = frame.Bones[j];

			if ( bone.parent >= 0 )
			{
				// transform bone position by parent orientation
				Bone &parentBone = frame.Bones[bone.parent];

				vec3f bonePos;
				bonePos.x = bone.position.x;
				bonePos.y = bone.position.y;
				bonePos.z = bone.position.z;

				vec3f vec = parentBone.orientation.QuatRotation(bonePos);

				// bone position = transformed position + parent position
				bone.position.x = vec.x + parentBone.position.x;
				bone.position.y = vec.y + parentBone.position.y;
				bone.position.z = vec.z + parentBone.position.z;

				bone.orientation = bone.orientation * parentBone.orientation;
			}
		}
If anyone's got any ideas, I'd be glad to hear them (other than give up!)

Share this post


Link to post
Share on other sites
Advertisement
That code doesnt seem right for animation, if your base pose is right (seems to be), the problem is on how you apply the information contained in the md5anim file, in there, you deal with vertices and weights rather than bones.

Share this post


Link to post
Share on other sites
That bit of code is required to get absolute values for the joint hierachy based on the relative values from the frame data in the md5anim file - but it's also the bit of code I most suspect as being 'wrong'. The md5anim doesn't even mention vertices and weights, they're all taken from the md5mesh file. md5anim only gives bone positions and orientations relative to parents.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ging
That bit of code is required to get absolute values for the joint hierachy based on the relative values from the frame data in the md5anim file - but it's also the bit of code I most suspect as being 'wrong'. The md5anim doesn't even mention vertices and weights, they're all taken from the md5mesh file. md5anim only gives bone positions and orientations relative to parents.


Ahh, yes my mistake, you don't seem to be processing the joint flags are you doing so before this snipet?

You first have to grab the baseframe position and rotation quaternion, then process the Joint Flags, replacing the values in the original Baseframe with the ones in Animated Components.

Then if the current joint doesnt have a parent (parentindex<0) set position and rotation as you got them after doing the replacements.

If it does have a parent then rotate the position vector using the parent quaternion, then to that vector add the position of the patent joint, you have the position for this joint.

Then the quaternion that represents the rotation is the parent quaternion multiplied by the rotation you got after processing the flags (IE the current local quaternion).

And thats it.

Share this post


Link to post
Share on other sites
I'm dealing with the components before this snippet - so the snippet deals with doing what you describe.

vec3f vec = parentBone.orientation.QuatRotation(bonePos);

is rotating the position vector by the parent quaternion.

bone.position.x = vec.x + parentBone.position.x;
bone.position.y = vec.y + parentBone.position.y;
bone.position.z = vec.z + parentBone.position.z;

updates the position with the new position + parent position

bone.orientation = bone.orientation * parentBone.orientation;

multiples the current quaterionion with the parent quaternion - is this in the wrong order? Should it be parent * current?

At least I'm doing roughly the right thing so far!

Share this post


Link to post
Share on other sites
Quote:
Original post by Ging
multiples the current quaterionion with the parent quaternion - is this in the wrong order? Should it be parent * current?

At least I'm doing roughly the right thing so far!


I have it as parent*current and my viewer works [wink]

Share this post


Link to post
Share on other sites
I just swapped them, no difference...

from what I can tell, I'm getting the information out of the file correctly - the component flags all match up and I'm using a copy of the baseframe then over writing the joints that have new values in each frame.

	vec3f QuatRotation(vec3f v)
{
Quaternion <T> qv(0, v.x, v.y, v.z);
Quaternion <T> qm = (*this) * qv * (*this).Inverse();

return vec3f(qm.x, qm.y, qm.z);
}


So it's either this bit of quat math, or something inherently wrong further up the chain - in which case, I'll have to get digging some more.

Share this post


Link to post
Share on other sites
It seems to be the way you're setting the first quaternion W value, I have:

inline void Set(float X, float Y, float Z)
{
x = X; y = Y; z = Z;
float term = 1.0f -
(x*x)-(y*y)-(z*z);
if (term < 0.0f)
{
w = 0.0f;
}
else
{
w = - sqrtf(term);
}
}

Share this post


Link to post
Share on other sites
I do that when I'm reading the frames and updating the joint data, after each quat is read I do the following to get the w.

float term = 1.0f - (bone.orientation.x*bone.orientation.x) - 
(bone.orientation.y*bone.orientation.y) -
(bone.orientation.z*bone.orientation.z);
float qw;
if (term < 0.0f)
qw = 0.0f;
else
qw = - (float) sqrt(term);

bone.orientation.w = qw;

Share this post


Link to post
Share on other sites
Ok, the last code you suspect is the code to get a vector rotated by the quaternion right?

In order to do that I first convert the quaternion to a matrix, I use OpenGL,
so if you're using Direct3D you'll have to swap rows for columns:


pMatrix[ 0] = 1.0f - 2.0f * ( y * y + z * z );
pMatrix[ 1] = 2.0f * (x * y + z * w);
pMatrix[ 2] = 2.0f * (x * z - y * w);
pMatrix[ 3] = 0.0f;

// Second row
pMatrix[ 4] = 2.0f * ( x * y - z * w );
pMatrix[ 5] = 1.0f - 2.0f * ( x * x + z * z );
pMatrix[ 6] = 2.0f * (z * y + x * w );
pMatrix[ 7] = 0.0f;

// Third row
pMatrix[ 8] = 2.0f * ( x * z + y * w );
pMatrix[ 9] = 2.0f * ( y * z - x * w );
pMatrix[10] = 1.0f - 2.0f * ( x * x + y * y );
pMatrix[11] = 0.0f;

// Fourth row
pMatrix[12] = 0;
pMatrix[13] = 0;
pMatrix[14] = 0;
pMatrix[15] = 1.0f;



Then I multiply the vector (in) against the matrix to get the final rotated vector (out)


out.v[X] = in.v[X] * matrix[0] + in.v[Y] * matrix[4] + in.v[Z] * matrix[8];
out.v[Y] = in.v[X] * matrix[1] + in.v[Y] * matrix[5] + in.v[Z] * matrix[9];
out.v[Z] = in.v[X] * matrix[2] + in.v[Y] * matrix[6] + in.v[Z] * matrix[10];



I believe this is the code for a Direct3D matrix:


out.x = in.x*matrix[0] + in.y*matrix[1] + in.z*matrix[2];
out.y = in.y*matrix[4] + in.y*matrix[5] + in.z*matrix[6];
out.z = in.z*matrix[8] + in.y*matrix[9] + in.z*matrix[10];



Anyway, this would at least give you something to check that your code is returning the proper vector.

You're not alone, getting it right gave me headaches too [smile]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!