Ragdoll mapping

Ragdoll mapping

I have a question about mapping ragdoll information onto a high res animation skeleton.

I have two poses, a low res ragdoll pose and a high res animation pose. I'm using the animation pose to place my graphics representation of the bones. I just have the animation pose set to the reference pose. I want to map the ragdoll bone positions onto the high res skeleton so I can have my graphical bones move with the ragdoll as it hits the ground etc, so I thought I would do this by mapping the low res onto the high res via:

hkaPose poseLowRes( m_ragdollInstance->getSkeleton() );
ragdollToHighResMapper->mapPose(poseLowRes, *poseHighRes, hkaSkeletonMapper::CURRENT_POSE);

however this gives some really screwy values for the bones unless I set the poseLowRes to the reference pose where I just get the unmoving reference pose. Does this mean that I need to "populate" the low res pose with the ragdoll positions? How would I go about doing this?

Thanks in advance for any help.

9 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Hi Aglet,
What are the values for poseHighRes when you call mapPose? The skeleton mapper will use the values that are already there to fill in information for the bones that it doesn't know about. For example, in a typical ragdoll, you don't have rigid bodies for the fingers, but the high-res pose might have these. Since the skeleton mapper doesn't have any information to go on, it will use the existing values in the high-res pose.

Typically, what happens is:
1) sample high-res animation
2) map high-res pose to ragdoll pose
3) drive ragdoll rigid bodies and step physics
4) map ragdoll pose to high-res pose
5) render

In step #4, you can reuse the high-res pose from step #1 and it should (hopefully) come out nice.

If you're still having trouble getting this going, you can try using something like what AnimationUtils::drawPose does to draw lines for both skeletons, and then look at the results in the Visual Debugger (it will see calls to e.g. HK_DISPLAY_LINE).

And if that still doesn't help, can you try reproducing the behavior by modifying one of the Havok demos? BlendTestDemo.cpp is probably a good start. Then depending on how that goes, try substituting your assets for ours. If you attach the demo (and assets if needed), we can take a closer look at what's going on...

-Chris

Just wondering - did you ever get this working?

Hi Chris,

It's partially working at the moment with a few issues I'm having troubles solving. Sorry for the long delay in a reply. The values for poseHighRes when I call mapPose are just the reference pose. I'm not actually sampling a high res animation yet, I just do steps 3 and 4 and use the high res bone positions as positions for my graphical representations bones (using Ogre3d). Thanks for your suggestion to look at BlendTestDemo, getPoseModelSpace was the step I was missing. My current code now makes the animation bones move with the ragdoll

hkLocalBuffer ragdollModelSpace( m_ragdollInstance->getSkeleton()->m_numBones );
hkaPose poseLowRes( m_ragdollInstance->getSkeleton() );
hkQsTransform::getIdentity() );
poseHighRes->setToReferencePose();

m_ragdollInstance->getPoseModelSpace( ragdollModelSpace.begin(), initialPos);

const hkQsTransform* localBIn = poseHighRes->getPoseLocalSpace().begin();
hkQsTransform* modelBOut = poseHighRes->accessPoseModelSpace().begin();

ragdollToHighResMapper->mapPose( ragdollModelSpace.begin(), localBIn, modelBOut, hkaSkeletonMapper::CURRENT_POSE );

For the "getPoseModelSpace( ragdollModelSpace.begin(), initialPos);" function call
I get initialPos as my world from model transform by getting the world transform of bone 0:

m_ragdollInstance->getWorldFromBoneTransform(0, initialPos);

Is this a valid way of doing this?

The major problem I'm having is getting the havok bone coordinates into valid coordinates for my graphical bone representation.

If I want to get the bone positions correct I need to swap Y & Z and inverse the new Z
I also need to multiply all the values by (1/2.54) * 100

setPosition(bonePos(0)*39.370106450488659622944808537836,bonePos(2)*39.370106450488659622944808537836,bonePos(1)*-39.370106450488659622944808537836);

This fixes my bone positions however I'm unsure how to successfully convert the rotations which is my major stumbling block at the moment.

Hi Aglet,
If you leave transform in getPoseModelSpace as hkQsTransform::getIdentity(), then the output from mapPose will already take the ragdoll's position into account (you can see this in the BlendTestDemo by setting the rigid bodies transparent with HK_SET_OBJECT_COLOR). So all you need to do is convert that output into your coordinate system. An easy way to do this is with hkaSkeletonUtils::transformModelPoseToWorldPose.

For transformModelPoseToWorldPose, the transform you want would (I think) be this:
hkRotation R;
R.getColumn(0).set(1,0,0);
R.getColumn(1).set(0,0,-1);
R.getColumn(2).set(0,1,0);

hkQsTransform T;
T.m_translation.setZero();
T.m_rotation = R; // this will convert from the 3x3 matrix to a quaternion
T.m_scale.setAll( 100.0f / 2.54f );

hkArray renderPose(numHiResBones);
hkaSkeletonUtils::transformModelPoseToWorldPose( numHiResBones, T, modelBOut, renderPose.begin() );

I'm pretty sure that will do the trick; let me know how it goes...

-Chris

Thanks for your help, the ragdoll is looking better but unfortunately I'm still having some problems

First I map the ragdoll onto the high res using this code which I think works fine:

m_ragdollInstance->getPoseModelSpace( ragdollModelSpace.begin(), hkQsTransform::getIdentity() );//initialPos);//

const hkQsTransform* localBIn = poseHighRes->getPoseLocalSpace().begin();
hkQsTransform* modelBOut = poseHighRes->accessPoseModelSpace().begin();

ragdollToHighResMapper->mapPose( ragdollModelSpace.begin(), localBIn, modelBOut, hkaSkeletonMapper::CURRENT_POSE );

Then I try to convert using this code:

hkRotation R;
R.getColumn(0).set(1,0,0);
R.getColumn(1).set(0,0,-1);
R.getColumn(2).set(0,1,0);

hkQsTransform T;
T.m_translation.setZero4();
T.m_rotation.set; // this will convert from the 3x3 matrix to a quaternion
T.m_scale.setAll( 100.0f / 2.54f );

hkArray renderPose(poseHighRes->getSkeleton()->m_numBones);
hkaSkeletonUtils::transformModelPoseToWorldPose( poseHighRes->getSkeleton()->m_numBones, T, modelBOut, renderPose.begin() );

Since I need the local space positions of the bones I figured I could get that by converting the worldPose back to a modelPose using the identity transform and storing it in modelBOut which is the model space of poseHighRes, then getting the local bone positions of poseHighRes.
hkaSkeletonUtils::transformWorldPoseToModelPose(poseHighRes->getSkeleton()->m_numBones,hkQsTransform::getIdentity(),renderPose.begin(), modelBOut);

while (savedBones < maxBones)
{
hkQsTransform boneTransform = poseHighRes->getBoneLocalSpace(savedBone);

Set Graphical bone[savedBone] position, rotation, scale to those in boneTransform
savedBone ++;
}

My first problem is that
T.m_scale.setAll( 100.0f / 2.54f );
doesn't actually make the bones farther apart, it just makes them much larger. So instead of getting a ball of body parts I get a chunkier ball of body parts.

So instead I set the m_scale to 1 and as I did previously increase the amounts the graphics bones are seperated when setting their position, while also swapping y & z and inversing the new z

setPosition(bonePos(0)* (100.0f / 2.54f), bonePos(2) * (100.0f / 2.54f), bonePos(1) * -(100.0f / 2.54f));

This makes the bones located the right distance apart. Unfortunately the rotations of the ragdoll still don't seem to be working as it twists oddly and seems to be facing the wrong way overall. I've attached a picture to show off the problem. Sorry for the lengthy explanation of what I'm doing, I just want to be sure I'm not acciden
tally breaking the rotation somehow. Thanks for all your help.

Attachments: 

AttachmentSize
Download comparison.PNG476.23 KB

Hey Aglet,
Sorry it's taking so long to get this working. I used to be good at this stuff, but I guess I'm getting rusty

Let's try this:
1) In the hkQsTransform I gave last time, keep the rotation and translation the way they are, and set scale to (1,1,1). This should be the right rotation for the transformation that you describe.
2) Call poseHighRes->accessPoseLocalSpace(); and copy the transforms into renderPose. This syncs the local space to the model space, just in case they got of of sync during the mapping.
3) Call renderPose[0].setMulEq( T ); This means that when the world space transforms of the bones are computed, the transform should automatically propagate to the child bones.

Hopefully, if you render at this point, things will look correct, just the right size. So we should just need to fix up the translations.

4) Multiply each of the hkQsTransforms::m_translation by 100/2.54

I sure hope that does the trick. It's possible that step #3 does a post-multiplication when it should be doing a pre-multiplication. If that's the case, then you can try
hkQsTransform temp;
temp.setMul( T, renderPose[0] );
renderPose[0] = temp;

Good luck!

-Chris

Sorry to be a bother but unfortunately I'm still having the same problem. :(

I map the ragdoll to the high res pose

then

hkRotation R;
R.getColumn(0).set(1,0,0);
R.getColumn(1).set(0,0,-1);
R.getColumn(2).set(0,1,0);

hkQsTransform T;
T.m_translation.setZero4();
T.m_rotation.set; // this will convert from the 3x3 matrix to a quaternion
T.m_scale.setAll( 1.0);

hkArray renderPose(poseHighRes->getSkeleton()->m_numBones);

renderPose = poseHighRes->accessPoseLocalSpace();

renderPose[0].setMulEq(T);

while (savedBones < maxBones)
{
hkQsTransform boneTransform = renderPose[savedBone]; //poseHighRes->getBoneLocalSpace(savedBone);

Set Graphical bone[savedBone] position to boneTransform translations multiplied by (100/2.54)

Set Graphical bone[savedBone]rotation, scale to those in boneTransform
savedBone ++;
}

The resulting ragdoll still has twisted bones and the positions of the bones are wrong.

If I fix the positions using

setPosition(bonePos(0)* (100.0f / 2.54f), bonePos(2) * (100.0f / 2.54f), bonePos(1) * -(100.0f / 2.54f));

then I think it's identical to the ragdoll I had in the last post where it's bones twist the wrong way and the ragdoll is overall facing the wrong direction.

The two variations of step 3 don't seem to make a difference.

Also this is probably completely unrelated but I seem to get smoother, less jerky movement of the ragdoll if I use

hkQsTransform boneTransform = poseHighRes->getBoneLocalSpace(savedBone);
instead of
hkQsTransform boneTransform = renderPose[savedBone]

I also printed out some of the bone rotations (in w,x,y,z format)for both the havok skeleton and the graphical skeleton being set to the reference pose but not synced, to try and see what was happening.

Havok Rot: 0.553133, 0.798534, 0.23221, -0.0496692
Ogre Rot: 0.553132, 0.798534, -0.0496692, -0.23221
HavokBipedRig L Finger0

Havok Rot: -0.547455, 0.799211, 0.243175, 0.0492188
Ogre Rot: 0.547454, -0.79921, -0.0492188, 0.243175
HavokBipedRig R Finger0

Havok Rot: -0.991715, 0.00285593, -0.0214049, -0.126637
Ogre Rot: 0.99784, -0.00146135, 0.0620416, -0.021545
HavokBipedRig L Foot

Havok Rot: -0.991712, -0.00292408, 0.0219257, -0.126567
Ogre Rot: 0.997833, 0.0014955, 0.0619725, 0.022069
HavokBipedRig R Foot

Havok Rot: 0.0215531, 0.0620412, -0.99784, -0.00133934
Ogre Rot: 0.997894, -2.40389e-011, -0.064865, 4.72051e-010
HavokBipedRig L Calf

Havok Rot: -0.0220769, 0.0619721, -0.997834, 0.00137458
Ogre Rot: 0.997894, 2.73818e-010, -0.064865, 3.62722e-009
HavokBipedRig R Calf

Havok Rot: 0.499999, 0.5, 0.500001, 0.5
Ogre Rot: 0.499074, -0.505013, -0.499527, 0.496347
HavokBipedRig Pelvis

I'm not really sure what to make of this as the problem seems to be different for each bone.

Hi aglet,

Can you try drawing out the orientations of all the bones. You could also try doing this in your modeller. What I am going for here is to make sure all the bones have a similar starting orientation.

One other thing to try is to take out parts of the rotation/position correction. Then adding those back into the code one at a time and seeing what the orientations look like.

Thanks,

Sean

Developer Support Engineer
Havok
www.havok.com

Leave a Comment

Please sign in to add a comment. Not a member? Join today