Topic: Bones manipulation

Bones positions are a bit weird, they have values like
0.640017
1.433489
etc
So I don't know how to retrieve the actual world coordinates of the bones.
I added the position of the parent entity of course, but this is not enough.

I need enlightenment about this.

Last edited by 255 (2014-02-09 15:45:45)

Re: Bones manipulation

To be correct you need to use the matrices, after the armature parenting is computed,
you multiply the entity matrix with the bone matrix :

MMatrix4x4 boneWorldMatrix = (*entity->getMatrix()) * (*bone->getMatrix());

All meshs are instances, so because multiples entities can use the same mesh
you need to update the armature for each entity (depending on the entity current animation) before retrieving the bone matrix :

MMesh * mesh = entity->getMesh();
if(mesh)
{
    MArmature * armature = mesh->getArmature();
    MArmatureAnim * armatureAnim = mesh->getArmatureAnim();
    if(armature)
    {
        // animate armature
        if(mesh->getArmature())
        {
            MArmature * armature = mesh->getArmature();
            if(mesh->getArmatureAnim())
            {
                animateArmature(
                    mesh->getArmature(),
                    mesh->getArmatureAnim(),
                    entity->getCurrentFrame()
                );
            }
            else
            {
                armature->processBonesLinking();
            }
        }
    }
}

this computation is otherwise only done at rendering if the entity is visible.

Re: Bones manipulation

Thank you for the fast reply.
I knew that you had to update the armature thanks to old threads.
What I was missing was the matrix stuff.
Getting the translation part of that matrix gave me a correct vector3 with world coordinates. Thank you very much.

You know, I suck at understanding matrixes in general and all the related transformation operations.
Do you have any tutorial/source/link where I could improve understanding these things in relation to game development?

Re: Bones manipulation

How do I now set the bone position to say world position P(0,0,0)?

Last edited by 255 (2013-08-18 22:36:40)

Re: Bones manipulation

To be be tested but you could do that (after parenting is computed) :

MObject3d * parentBone = bone->getParent();
MVector3 P_entity = entity->getInversePosition(P); // entity space

if(parentBone)
{
    MVector3 P_parent = parentBone->getInversePosition(P_entity); // bone parent space
    bone->setPosition(P_parent);
}
else
{
     bone->setPosition(P_entity); // no parent so the bone is in entity space
}

[EDIT : modified "MObject3d * parentBone"]

Re: Bones manipulation

About math and matrices :
- http://www.gamedev.net/page/resources/_ … ices-r3097
- http://www.gamedev.net/page/resources/_ … ified-r695

Re: Bones manipulation

It was

MObject3d * parentBone = bone->getParent();

The rest works fine. Thank you, especially for the links. smile

Re: Bones manipulation

So I was trying to do the same with rotation, and of course I'm failing.
Basically I have to copy the rotation of an object to the rotation of the bone to create a ragdoll.

Last edited by 255 (2013-10-06 10:07:35)

Re: Bones manipulation

It will be again a matrix operation, by head I'll say :

// calculate object matrix in boneEntity's space coordinate : "object" is the object to copy transformation from
MMatrix myMatrix = boneEntity->getMatrix()->getInverse() * (*object->getMatrix());

// if "bone" is linked to another bone
MObject3d * parentBone = bone->getParent();
if(parentBone)
{
    // calculate object matrix in parentBone's space coordinate
    myMatrix = parentBone->getMatrix()->getInverse() * myMatrix;
}

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

ps : getInverse() returns the inverse matrix of a matrix
(to be tested)

10

Re: Bones manipulation

With this code, while the object rotates in the Y axis, the bone rotates in the Z axis.

Re: Bones manipulation

this can be because bones can be oriented in various direction,
blender normally export bones that are Y aligned (meaning the bone length will be locally parallel to Y),
other softwares can align bones on different axis.

If you exported from Blender try to use a box as object and scale it longer on Y to make a stick and see if it synchronize with the bone.

Because normally the code is good.

12

Re: Bones manipulation

I already tried to set bones rotation to zero in Blender, but it was all the mesh that was rotated towards the wrong axis eheh. Now it works.

13

Re: Bones manipulation

Here I am again with my total lack of success with matrices and rotations. And I'm sorry to post again but I've lost way too much time on this trying to get it to work.
I'm trying to copy the rotation from a bone to another bone.
You provided me the code for copying the rotation from an object to a bone, here http://forum.maratis3d.com/viewtopic.php?pid=5346#p5346 , so I thought that basing on that, I could do:

                MMatrix4x4 myMatrix = (*entity->getMatrix()) * (*boneToCopyFrom->getMatrix());
                MObject3d* parentBone = bone->getParent();
                if(parentBone)
                    myMatrix = parentBone->getMatrix()->getInverse() * myMatrix;
                bone->setEulerRotation(myMatrix.getEulerAngles());

but the final rotation is not as expected.
p.s. I want to copy bone world position to bone world position.

Re: Bones manipulation

are the two bones in the same armature ? or not necessary ?

15

Re: Bones manipulation

Yes, in the same armature. So, for example, the arm is controlled by two overlapping structures of bones and I want one to overlap the other copying rotation and position. Position works (using the code of your first post in this thread), rotation doesn't (with the code I posted last).

Last edited by 255 (2013-11-23 12:35:10)

Re: Bones manipulation

Probably something like that :

// targetBone is the bone to copy the transformation from
// bone is the bone to copy the transformation to
// the two bones need to be in the same armature

MMatrix targetMatrix = (*targetBone->getMatrix()); // get target bone matrix (in armature space)

// if "bone" is linked to another bone
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());

What is important is to know what space you are, world space, armature space or parent space.

17

Re: Bones manipulation

Mmm.. doesn't work.
I'll try to set up a very simple and basic scene to do some testing with. It will take some time but at least I can be sure the error is somewhere else, I have too much code here.

18

Re: Bones manipulation

Yes, it works, and if the bones really overlap you can also simply do

bone->setRotation(targetBone->getRotation());

and that's enough. In other cases your code works better.
So, yeah, the problem lies somewhere else in my code.
Debugging time! lol
Thanks for the help.

Re: Bones manipulation

bone->setRotation(targetBone->getRotation()); will work only if both bones are not parented or if they are linked to the same parent.

Because otherwise they are not in the same space, and you need to use the code I gave you (that use the inverse matrix of the parent if there is a parent).

20

Re: Bones manipulation

I'm back working on my ragdoll system and I have problems.

I have a ragdoll made of ragdoll parts.
Each ragdoll part is just a parallelepiped entity which visually simulates the bone.
Each ragdoll part is in world space (they are parented only with constraints).
I have a characterEntity and its armature.
The armature should "follow" the ragdoll (and this is what is not quite working).

First, at the start of the game, I position and rotate each ragdoll part, copying the position and rotation from the bones.
Then, I let the physics run and each step I do the inverse: I rotate every bone to match the ragdoll part rotation, so the mesh should animate and fall down to the floor.

It works almost fine but there is some kind of offset, e.g. the leg's bone is ~15° off on the X axis in respect to the ragdoll part, the arm's bone ~ the same, etc.
The ragdoll is currently only about the skeleton, so it's not about e.g. the arm not being perfectly in line with the bone or uncorrectly colliding: I'm making a ragdoll of the skeleton only. Only when this works, I will attach actual body parts for the collisions.

My code is actually pretty long, complex, and separated into classes and files, I just can't post it all. But I'm pretty sure the problem is only about matrices and rotation, and lies here:

[...]
        //Ragdoll's part copys rotation from bone (works perfectly fine)
        MMatrix4x4 boneWorldMatrix = (*characterEntity->getMatrix()) * (*bone->getMatrix());
        ragdollPart->setEulerRotation(boneWorldMatrix.getEulerAngles());
[...]
        //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());
[...]

http://oi61.tinypic.com/1zdxkpe.jpg
The grey lines are the ragdoll parts. They are in "x-ray mode".
The red little squares are the bones (the head of every bone).
In the image on the left, the game is just started, and everything is right. The ragdoll parts are positioned and rotated copying the bones position and rotation from the armature.
As soon as I activate the physics (only one step of physics), you can see how the bones don't match the ragdoll parts correctly.

Last edited by 255 (2014-02-09 17:00:25)

Re: Bones manipulation

This looks interesting, wish I could help, but I'm too simple for this complexity, haha. Hopefully someone will chime in, I'm curious as to what the issue could be.

How do you get the orientation of your bones? Perhaps a visual cue for that would be something you could add.

22

Re: Bones manipulation

Well it's actually complex for me too, I've still not grasped matrices and stuff quite well I guess eheh.

Tutorial Doctor wrote:

Perhaps a visual cue for that would be something you could add.

There's no need. Since I never change the position (only at the start) and I change only the orientation of the bones, you can be sure that the orientation is simply what goes from a red dot to the other. The position changes automatically thanks to parent-child relationships between the bones, as a "side-effect" of the rotation changes.

Last edited by 255 (2014-02-09 17:52:51)

Re: Bones manipulation

You have to process the bones in the right order, from the roots to the childs.
It should be something like that :

void copyTransformation(MOEntity * entity, MOBone * bone, MObject3d * object)
{
    MMatrix4X4 targetMatrix = entity->getMatrix()->getInverse * (*object->getMatrix()); // get object matrix in armature space

    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());
    bone->computeLocalMatrix();
}

void processChilds(MOEntity * entity, MOBone * bone)
{
    unsigned int i, childsNumber = bone->getChildsNumber();

    for(i=0; i<childsNumber; i++) // for all childs
    {
        MOBone * child = (MOBone *)bone->getChild(i);
        MObject3d * object = ... // get the associated ragdol object

        // compute parenting (parent matrix * child local matrix)
        copyTransformation(entity, child, object);
        (*child->getMatrix()) = (*bone->getMatrix()) * (*child->getMatrix());
        processChilds(entity, child);
    }
}

and during the update :

// start from the roots to the childs
for(i=0; i<bonesNumber; i++)
{
    MOBone * bone = armature->getBone(i);
    if(! bone->hasParent())
    {
        MObject3d * object = ... // get the associated ragdol object
        copyTransformation(entity, bone, object);
        processChilds(entity, bone);
    }
}

And in this case you don't need to call "armature->processBonesLinking();"

24

Re: Bones manipulation

My for loop is

for(i=0; i<bonesNumber; i++)

and the mesh has one single root bone, which is bone 0.
After each bone is rotated, I do:

armature->processBonesLinking();
armature->updateBonesSkinMatrix();

inside the brackets of the for loop, and then I process the next bone (i++).
So I don't really think that the problem is about order.

I will try your code anyway and let you know.

Last edited by 255 (2014-02-09 20:32:07)

25

Re: Bones manipulation

Not quite right.
http://oi62.tinypic.com/1zqwpsk.jpg

LOL.
In the processChilds function of your code I think this lines:

        // compute parenting (parent matrix * child local matrix)
        copyTransformation(entity, bone, object);
        (*child->getMatrix()) = (*bone->getMatrix()) * (*child->getMatrix());
        processChilds(entity, child);

should actually be:

        // compute parenting (parent matrix * child local matrix)
        copyTransformation(entity, child, object);   //   <--------
        (*child->getMatrix()) = (*bone->getMatrix()) * (*child->getMatrix());
        processChilds(entity, child);

otherwise it doesn't make sense.

Compiling with this correction I get the exact same result of the first image that I've posted (the one on the right), which is: the rotation is not quite right.

So as I thought it's not about the order. IMHO some matrix operation is not correct. Or the bug may be somewhere else, but I triple-checked every single line of my code.

Last edited by 255 (2014-02-09 21:30:57)