Re: Bones manipulation

yes should be child.
the order is important, because you need the parent matrix to be updated to get the correct child matrix.

27

Re: Bones manipulation

Yes, the order is important but I got it right.
I use a makehuman mesh (basic rig), the bones are already put in a decent order in the mesh file and there is only one root bone, so your code solution is not required.

Anyway, both my original code and yours give the same result.
So the bug is not about the order.

Last edited by 255 (2014-02-09 22:32:18)

Re: Bones manipulation

I don't see something wrong in the code, if you get the same result, your code is right too, but you should not call "armature->processBonesLinking();" multiple time in your loop (it's slow because it update all the armature each time).

So if it's not that, the problem should be that the bones and the ragdoll objects axis are not synchronized :
- because the ragdoll objects are not oriented the same axis as the bones
- or because the bones are not oriented in a consistent way

Lets say they are not synchronized, but you manually placed the ragdoll on the first frame.
You can calculate the offset matrix at the first frame and store it.
Then, when you update the bones, you use this offset.

Re: Bones manipulation

For the offset calculation, I'm not totally sure, but it should be something like that (to be tested) :

// call this only at the first frame
MMatrix4X4 boneWorldMatrix = (*entity->getMatrix()) * (*bone->getMatrix());
MMatrix4X4 offsetMatrix = object->getMatrix()->getInverse() * boneWorldMatrix;
... // store the offset matrix
void copyTransformation(MOEntity * entity, MOBone * bone, MObject3d * object, MMatrix4X4 * offsetMatrix)
{
    MMatrix4X4 correctedWorldMatrix = (*object->getMatrix()) * (*offsetMatrix);
    MMatrix4X4 targetMatrix = entity->getMatrix()->getInverse * correctedWorldMatrix;

    *bone->getMatrix() = targetMatrix; // this is the actual armature space matrix

    // what comes after is only used to update the local coordinates position and rotation
    MObject3d * parentBone = bone->getParent();
    if(parentBone)
    {
        // calculate target matrix in parentBone's space
        targetMatrix = parentBone->getMatrix()->getInverse() * targetMatrix;
    }

    // get position and rotation coords from targetMatrix
    bone->setPosition(targetMatrix.getTranslationPart());
    bone->setEulerRotation(targetMatrix.getEulerAngles());
}

If you are 100% sure the bones are sorted, you can simplify the call :

for(i=0; i<bonesNumber; i++)
{
    MObject3d * object = ... // get the ragdoll
    MMatrix4X4 * offsetMatrix = ... // get the offset matrix
    copyTransformation(entity, armature->getBone(i), object, offsetMatrix);
}

// no need to call armature->processBonesLinking();
armature->updateBonesSkinMatrix(); // optional, is normally called by the renderer

30

Re: Bones manipulation

Your code as it is makes everything blow up, similarly to the previous image that I've posted.
But I think we're on the right path.
I remember having tried something similar in the past: http://forum.maratis3d.com/viewtopic.php?pid=5562#p5562
although the situation was a bit different. But yes, I also thought about the offset so I guess this is the way to go.
Still, the code as it is doesn't seem to work.

If nothing works I could use that old code of mine, but it's not that good because it uses a specific axis which may be different depending on where the bone is (e.g. leg and arms need a different calculation). So using matrices should be better.

Last edited by 255 (2014-02-10 00:27:27)

Re: Bones manipulation

What I specially have a doubt is the order of the matrix multiplication for the offset, I need to check my math.

What you should do to check this potential axis problem is to visualize the bones in space,
disable the physics and all the parenting of your ragdoll objects and copy the bones transformation to the ragdoll objects.
At least you'll be able to see how the bones are oriented.

MMatrix4X4 boneWorldMatrix = (*entity->getMatrix()) * (*bone->getMatrix);
*object->getMatrix = boneWorldMatrix;
object->setPosition(boneWorldMatrix.getTranslationPart());
object->setEulerRotation(boneWorldMatrix.getEulerAngles());

32

Re: Bones manipulation

I've disabled the physics (commented every part of code which has something to do with the physics).
Ragdoll parts have now no parent-child relationships, no physics and no constraints.
Copying the bone rotation and position from the armature to the ragdoll, the result is what is seen in the first image that I've posted (the one on the left): http://forum.maratis3d.com/viewtopic.php?pid=6377#p6377, as expected.
Which is the default position of the armature, the same that it's on the Blender file.

If this is of any help, in the Blender file the bones in their default position (as seen in the image) are considered to be at rotation zero (0,0,0) on the 3 axis. In Maratis tough it's not the same, because if I set them at (0,0,0) they all point straight to the axis +Y.

Last edited by 255 (2014-02-10 11:20:57)

Re: Bones manipulation

I made a small example with a behavior code to attach a bone to an entity : http://www.maratis3d.org/download/Armature.zip

After compiling, open the project.
Select "Jules" and look at the behaviors.
You can see the effect in-editor by moving the transparent boxes.

34

Re: Bones manipulation

Ah! You did it!
And there's no need to call armature->processBonesLinking() or bone->computeLocalMatrix().
Thank you very much anael.

Re: Bones manipulation

It's maybe not optimal for you as you are updating the full armature, but it can help you debug your code or prototype ?
Let me know if it worked with your armature.

36

Re: Bones manipulation

Yes your code works perfectly in my project too.
Your "CopyTransformation" function as it is in your zip file is everything I needed.
In my first post about this problem I wrote that the part that I suspected was not working was this:

  //Bone copys from Ragdoll's part (DOESN'T WORK)
        MMatrix4x4 myMatrix = characterEntity->getMatrix()->getInverse() * (*ragdollPart->getMatrix());
        MObject3d* parentBone = bone->getParent();
        if(parentBone)
            myMatrix = parentBone->getMatrix()->getInverse() * myMatrix;
        bone->setEulerRotation(myMatrix.getEulerAngles());

And indeed replacing this with your code solved everything. Now the ragdoll works fine. smile
It was that "no scale" trick that was missing.

Last edited by 255 (2014-02-10 16:38:15)

Re: Bones manipulation

good smile

yes, that's what I figured out, a non-uniform scale (not the same scale on each axis) can deform the rotation angles, it's a bit tricky.