model animation

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

Recommended Posts

I'm trying to get ms3d animation working using the code from rsn.gamedev.net modified to fit into my math code and the unfunctioning framework I had before I found that site. However, I've run into some problems, it appears that the joints are being rotated in place correctly but not being translated to be in the correct place in relation to the parent joint. I think it has to just be something stupid I'm missing, but I've been searching around for two days and have found nothing, and I can't get the actual code used from rsn, I'm at a loss. I'll just post pretty much everything, great thanks to anyone willing to spend the time to look through it. SetupJoints:
Matrix33 invmat;
m_Joints[x].m_Relative = Matrix33::BuildRotationMatrix(m_Joints[x].m_Rotation.x,
m_Joints[x].m_Rotation.y, m_Joints[x].m_Rotation.z);

invmat = Matrix33::BuildRotationMatrix(-m_Joints[x].m_Rotation.x,
-m_Joints[x].m_Rotation.y, -m_Joints[x].m_Rotation.z);

if(m_Joints[x].m_ParentJoint != -1)
{
m_Joints[x].m_Absolute = m_Joints[m_Joints[x].m_ParentJoint].m_Absolute * m_Joints[x].m_Relative;
m_Joints[x].m_AbsoluteInverse = m_Joints[m_Joints[x].m_ParentJoint].m_AbsoluteInverse * invmat;
m_Joints[x].m_AbsoluteTranslation = m_Joints[m_Joints[x].m_ParentJoint].m_AbsoluteTranslation + m_Joints[x].m_Translation;
}
{
m_Joints[x].m_Absolute = m_Joints[x].m_Relative;
m_Joints[x].m_AbsoluteInverse = invmat;
m_Joints[x].m_AbsoluteTranslation = m_Joints[x].m_Translation;
}

//transfor joint's vertices back to origin so we don't have to do it each frame
for(uint i=0; i<m_Joints[x].m_NumVertices; ++i)
{
Vertex& vert = m_Vertices[m_Joints[x].m_Vertices];
vert.SetCoordinates(vert.GetCoordinates() - m_Joints[x].m_AbsoluteTranslation);
vert.SetCoordinates(vert.GetCoordinates()*(m_Joints[x].m_AbsoluteInverse));

//also need to transform normals
vert.SetNormal(vert.GetNormal()*(m_Joints[x].m_AbsoluteInverse));
}


for(uint x=0; x<m_NumJoints; ++x)
{
Vector3 trans; Quaternion rot;
while(m_Joints[x].m_RotationKeyframes[m_Joints[x].m_CurRotKeyframe].m_Time < m_CurTime &&
m_Joints[x].m_CurRotKeyframe <= m_Joints[x].m_NumRotationKeyframes)
++m_Joints[x].m_CurRotKeyframe;

if(m_Joints[x].m_CurRotKeyframe == 0)
rot = Quaternion::BuildFromEulerAngles(m_Joints[x].m_RotationKeyframes[0].m_Data);
else if(m_Joints[x].m_CurRotKeyframe >= m_Joints[x].m_NumRotationKeyframes)
rot = Quaternion::BuildFromEulerAngles(m_Joints[x].m_RotationKeyframes[m_Joints[x].m_NumRotationKeyframes-1].m_Data);
else
{
ModelKeyframe& prevFrame = m_Joints[x].m_RotationKeyframes[m_Joints[x].m_CurRotKeyframe-1];
ModelKeyframe& curFrame = m_Joints[x].m_RotationKeyframes[m_Joints[x].m_CurRotKeyframe];

//need to interpolate values
float interpolation = (float)(m_CurTime - prevFrame.m_Time) /
(curFrame.m_Time - prevFrame.m_Time);

Quaternion prev = Quaternion::BuildFromEulerAngles(prevFrame.m_Data);
Quaternion cur = Quaternion::BuildFromEulerAngles(curFrame.m_Data);
rot = Quaternion::Slerp(prev, cur, interpolation);
}

//find translation
while(m_Joints[x].m_TranslationKeyframes[m_Joints[x].m_CurTransKeyframe].m_Time < m_CurTime &&
m_Joints[x].m_CurTransKeyframe <= m_Joints[x].m_NumTranslationKeyframes)
++m_Joints[x].m_CurTransKeyframe;

if(m_Joints[x].m_CurTransKeyframe == 0)
trans = m_Joints[x].m_TranslationKeyframes[0].m_Data;
else if(m_Joints[x].m_CurTransKeyframe >= m_Joints[x].m_NumRotationKeyframes)
trans = m_Joints[x].m_TranslationKeyframes[m_Joints[x].m_NumTranslationKeyframes-1].m_Data;
else
{
ModelKeyframe& prevFrame = m_Joints[x].m_TranslationKeyframes[m_Joints[x].m_CurTransKeyframe-1];
ModelKeyframe& curFrame = m_Joints[x].m_TranslationKeyframes[m_Joints[x].m_CurTransKeyframe];

//need to interpolate values
float interpolation = (float)(m_CurTime - prevFrame.m_Time) /
(curFrame.m_Time - prevFrame.m_Time);

trans = prevFrame.m_Data;
trans += (curFrame.m_Data - prevFrame.m_Data) * interpolation;
}

//create final mat and transform to use when moving verts
m_Joints[x].m_FinalMat = m_Joints[x].m_Relative * rot.BuildRotationMatrix();
m_Joints[x].m_FinalTransformation = m_Joints[x].m_Translation + trans;

//now we need to use our parent ro make the final absolute instead of relative
if(m_Joints[x].m_ParentJoint != -1)
{
m_Joints[x].m_FinalMat = m_Joints[m_Joints[x].m_ParentJoint].m_FinalMat * m_Joints[x].m_FinalMat;
m_Joints[x].m_FinalTransformation = m_Joints[m_Joints[x].m_ParentJoint].m_FinalTransformation + m_Joints[x].m_FinalTransformation;
}

//transformify the vertices
for(uint i=0; i<m_Joints[x].m_NumVertices; ++i)
{
uint vert = m_Joints[x].m_Vertices;
m_TransformedVerts[vert].SetCoordinates((m_Vertices[vert].GetCoordinates()
* m_Joints[x].m_FinalMat) + m_Joints[x].m_FinalTransformation);

m_TransformedVerts[vert].SetNormal(m_Vertices[vert].GetNormal() * m_Joints[x].m_FinalMat);
//all other parts of transformed verts must have been set during initialization
}
}



Share on other sites
probably a stupid question, but have you verified that ParentJoint is being stored (i.e. not a -1)?

Share on other sites
Yes, all but the first joint(obviously) have a parent.

Share on other sites
God I hate to bump, and I know it's a lot of code for someone to read through, but I really need some help. It seems like I should just have to do some translation before rotating to get it to follow the parent node's movement but it always ends up really deformed.

Share on other sites
Consider this half a bump and half a suggestion... sorry i dont have the stomach to look through anyone elses code right now (im sick enough of my own) :-p but ill just throw a couple things out there...

for skeletal animation.... the final matrix is all of the parent matrices ADDED together... i know that threw me at first...

does the bind pos work?

what are the symptoms? legs shooting every which way? :-D

heh, not much of a help but i gave it a shot lol
-Dan

Share on other sites
Yeah the final matrix is a cumulative multiplication of all the parent matrices.

Not entirely sure what you mean by the bind pos?

At first glance it looks like it's just the joints not getting translated correctly to the end of the parent joints. Like the joints all rotate in place but never move. It seems like it should be something obvious that I'm missing, but I really can't find it, with the number of times I think I could be overlooking just about anything.

Thanks for the ideas, beggars can't be chosers.

Share on other sites
well... this may be wrong... but it believe its supposed to be the ADDITION rather than the multiplication of the bones... i know it seems counter intuitive... but hey... its worth a shot right? (its possible that i heard wrong... but as i said... its probably worth a shot)

-Dan

Share on other sites
Neah, it IS multiplication.

I've implemented animation for Blizzard's MDX/MDL models a while ago, so I can list some things that I've been doing wrong(until I've found and correct them in the end):
- check the order of multiplications - rotations or translations first?
- check the order of linking with parent matrix, it is different when you are using left-handed or right-handed coordinates.

Quote:
 //create final mat and transform to use when moving vertsm_Joints[x].m_FinalMat = m_Joints[x].m_Relative * rot.BuildRotationMatrix();m_Joints[x].m_FinalTransformation = m_Joints[x].m_Translation + trans;

- I'm pretty sure you should apply parent's transformation to your _m_FinalTransformation_ vector (consider your model's left hand moves to the left - when the corpus is rotated(pi/2 to the right), the hand moves forward!!), considering the symptoms it seems that here is the main case hidden...
- you should assure, that the joints' final matrices are computed in BFS order in the skeletal-tree,

And one more: I was using 4x4 matrices only, so I wouldn't have to worry about rotations and translations inheritance, just the final matrix...

That's all that came to my mind on-the-fly.
Hope there's nothing left ;)
/def

Share on other sites
Crazed:
Grab the MSViewer demo from MilkShape and have it compile (yes, I know it is OGL, do it nonetheless). Then be sure that the exact same data is loaded into both your program and MSViewer.

After that, you debug, stepping through each line in both your program and MSViewer, and compare the results of each step.

I can recommend locking the AdvanceFrame to a fixed number (in the beginning of AnimationAdvance() I put a line:

m_currenttime = 12.0f; (or 0.5f if you use from 0-1 instead of 1-FPS, like MSViewer does).

This effectively locks the frame at one specific time, which makes it easy for you to compare.

I can't be arsed to parse through your code, but here you have some hints to how I got it to work.

PS:
When you test, then don't bother with RH->LH conversions. The data for both programs has to be the same.

Share on other sites
This was covered by a previous poster, but the translation component isn't quite right. Everything else looks correct to me, although 4x4 matrices do make this a bit easier in my opinion.

m_Joints[x].m_AbsoluteTranslation =    m_Joints[m_Joints[x].m_ParentJoint].m_AbsoluteTranslation   + m_Joints[x].m_Translation;

You should rotate the current bone's translation by the parent bone's orientation before adding in the parent bone's translation. Otherwise you're not translating in the right directions away from the parent bone.

m_Joints[x].m_AbsoluteTranslation =     (m_Joints[x].m_Translation * m_Joints[m_Joints[x].m_ParentJoint].m_Absolute)    + m_Joints[m_Joints[x].m_ParentJoint].m_AbsoluteTranslation;

• Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 15
• 22
• 17
• 46