Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

rgreene

Needs help with my CCD system

This topic is 5242 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 just got my CCD IK implementation working and I have a question about it. When I apply the algorithm to something like a character''s arm, you end up having twisting on some of the bones. While the system is technically solving the system (ie the bones are indeed pointing towards the goal point), the result looks poor. For implemeting a head-look-at solver, I ran into the same thing, however I was able to solve the sitaution by taking my output and rotating the bone about it''s axis so that it points as much "up" as it can (if that makes sense). However, with an arbitrary bone linkage, such as a characters arm, I don''t see how I can use the same kind of cheat. This is my main concern.

Share this post


Link to post
Share on other sites
Advertisement
Well, I came up with a solution, but it requires a whole lot of extra math... here''s my ik algorithm:


tQuatBone *IKBones[3];
float initialBoneRotation[3];
int itteration, bone, i;
tPoint3 affectorPoint;
tPoint3 targetVector, goalVector, orthoAxis;
tPoint3 u, v, w;
tQuaternion q, inverseParent, baseRotation;
float theta;

if (!fTargetPoint)
return kFalse;

IKBones[0] = skeleton->mGetBone ("L Wrist01");
IKBones[1] = skeleton->mGetBone ("L ForeArm02");
IKBones[2] = skeleton->mGetBone ("L UpperArm02");

// get our initial rotations
for (bone = 0; bone < 3; bone++)
{
u.mSet (0, 1, 0);
v.mSet (0, 1, 0);
w.mSet (1, 0, 0);
IKBones[bone]->fParent->fOutput.mTransform (u);
IKBones[bone]->fParent->fOutput.mTransform (w);
IKBones[bone]->fOutput.mTransform (v);

w = w.mCrossProduct (u);
theta = acos (u.mDotProduct (v));

if (w.mDotProduct (v) > 0.0f)
initialBoneRotation[bone] = theta;
else
initialBoneRotation[bone] = 3.14159 + (3.14159 - theta);
}

for (itteration = 0; itteration < 10; itteration++)
{
for (bone = 0; bone < 3; bone++)
{
affectorPoint.mSet (IKBones[0]->fLength, 0, 0);
IKBones[0]->fOutput.mTransform (affectorPoint);
affectorPoint += IKBones[0]->fFinalWorldPosition;

targetVector = affectorPoint - IKBones[bone]->fFinalWorldPosition;
targetVector.mNormalize ();

goalVector = *fTargetPoint - IKBones[bone]->fFinalWorldPosition;
goalVector.mNormalize ();

orthoAxis = targetVector.mCrossProduct (goalVector);
orthoAxis.mNormalize ();

q.mCreateRotation (orthoAxis, acos (targetVector.mDotProduct (goalVector)));
inverseParent = IKBones[bone]->fParent->fOutput.mInverse ();
q = q * IKBones[bone]->fOutput;
IKBones[bone]->fBaseOutput = inverseParent * q;

for (i = bone; i >= 0; i--)
IKBones->mUpdateBone ();
}
}

// now fix up the rotations based on the initial rotations (for all bones but the lowest bone)
for (bone = 1; bone >= 0; bone--)
{
u.mSet (0, 1, 0);
v.mSet (0, 1, 0);
w.mSet (1, 0, 0);
IKBones[bone]->fParent->fOutput.mTransform (u);
IKBones[bone]->fParent->fOutput.mTransform (w);
IKBones[bone]->fOutput.mTransform (v);

w = w.mCrossProduct (u);
theta = acos (u.mDotProduct (v));

if (w.mDotProduct (v) > 0.0f)
q.mCreateRotation (1, 0, 0, -theta + initialBoneRotation[bone]);
else
q.mCreateRotation (1, 0, 0, -(3.14159 + (3.14159 - theta)) + initialBoneRotation[bone]);

IKBones[bone]->fBaseOutput *= q;

// send this down the heirarchy
for (i = bone; i >= 0; i--)
IKBones[i]->mUpdateBone ();

}

// treat the lowest bone special
{
tPoint3 forward, up, right, idealUp;

forward.mSet (1, 0, 0);
up.mSet (0, 1, 0);
idealUp.mSet (0, 0, 1);

IKBones[2]->fOutput.mTransform (forward);
IKBones[2]->fOutput.mTransform (up);

idealUp -= forward * idealUp.mDotProduct (forward);
idealUp.mNormalize ();

right = idealUp.mCrossProduct (forward);

if (up.mDotProduct (right) > 0.0f)
q.mCreateRotation (1, 0, 0, acos (up.mDotProduct (idealUp)));

else
q.mCreateRotation (1, 0, 0, -acos (up.mDotProduct (idealUp)));

IKBones[2]->fBaseOutput *= q;
IKBones[2]->mUpdateBone ();
}


I spend a whole bunch of time fixing the bone-spinning... is there a bette way to do this?

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!