Sign in to follow this  
Ging

MD5 animation issues

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
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
I've now got it to the point where about half the mesh animates correctly - for pinky it's his front half, his rear legs just go crazy however, but it's late and I need to be up shortly, I'll have to try some more in the morning.

[Edited by - Ging on June 11, 2006 10:16:23 PM]

Share this post


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


ging, i am really interested in the part you deal with the components flags. that's the point where i am stuck at the moment.

i would be very grateful if you could post the part of the source where the components influence the animation.

thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by Ging
I've now got it to the point where about half the mesh animates correctly - for pinky it's his front half, his rear legs just go crazy however, but it's late and I need to be up shortly, I'll have to try some more in the morning.


If you're doing the idle1 animation, I noticed that yes, the rear legs DO act all twitchy and whatnot. Check out the model in Doom 3, it's the same way.

Share this post


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


ging, i am really interested in the part you deal with the components flags. that's the point where i am stuck at the moment.

i would be very grateful if you could post the part of the source where the components influence the animation.

thanks!


Basically, the component flags tell you which joint translation/rotation components are different from the base frame. You simply replace the base frame values with the ones that are indicated as different.

Share this post


Link to post
Share on other sites
Quote:
Original post by PfhorSlayer
Basically, the component flags tell you which joint translation/rotation components are different from the base frame. You simply replace the base frame values with the ones that are indicated as different.


thanks very much, that explains a lot!

interestingly when i export from 3dsmax, all my values are 63, although some bones do not move at all. do you know what i could be doing wrong in 3dsmax?

thanks!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
ehmdjii,
I bet the exporter simply write all components to the md5 file, whether they are animated in max or not

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this