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.
You are not logged in. Please login or register.
yes should be child.
the order is important, because you need the parent matrix to be updated to get the correct child matrix.
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)
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.
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
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)
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());
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)
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.
Ah! You did it!
And there's no need to call armature->processBonesLinking() or bone->computeLocalMatrix().
Thank you very much anael.
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.
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.
It was that "no scale" trick that was missing.
Last edited by 255 (2014-02-10 16:38:15)
good
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.
Powered by PunBB, supported by Informer Technologies, Inc.
Currently installed 3 official extensions. Copyright © 2003–2009 PunBB.