Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am writing a simple BVH parser in C# using the XNA framework. At the moment I have managed to parse in all the data and my goal is to find out the global coordinates of all the joints in the skeleton.

The problem I am encountering is that the bones don't seem to take into account the rotation of its parents. For instance if I move my lower leg, I would expect my foot to change orientation as well and keep the same angles between the foot and the lower leg. What I am noticing is that the translation of the bone joints are correct, but the global rotation of a bone is the same as the local rotation of the bone. The picture below might help you understand what the problem is:

http://i40.tinypic.com/18kv2d.png

note: there is a mistake in the pic captions, it should read "the left upper leg is rotated around the z axis" not the x axis.

I would have expected the lower leg portion to also be rotated by 1 radian a a result of its parents change in orientation.

So the code is as below (I am using XNA and C#):

foreach (Bone b in bones)
{
            //Calculate the local transform matrix
            b.localTransform = Matrix.CreateTranslation(b.Offset) * Matrix.CreateRotationZ(MathHelper.ToRadians(b.z)) * Matrix.CreateRotationY(MathHelper.ToRadians(b.y)) * Matrix.CreateRotationX(MathHelper.ToRadians(b.x));
            Bone parent = b.parent;
            if (parent != null)
            {
                //Calculate global transform matrix
                b.globalTransform = parent.globalTransform * b.localTransform;
                b.location = b.globalTransform.Translation;
                lines.Add(new Tuple<Vector3, Vector3>(parent.location, b.location));
            }
}

Each bone assumes its parents global transformation is correct as the list is ordered so the parents always come before the children. The root bone has no rotations and no offset and has its global transform already set based on this. I am wondering what I am doing wrong here?

I have done a simple example using only 2D:

Matrix bone1 = Matrix.CreateTranslation(new Vector3(3, 0, 0)) * Matrix.CreateRotationZ(1); 
Matrix bone2 = Matrix.CreateTranslation(new Vector3(3, 0, 0)) * Matrix.CreateRotationZ(1); 

lines.Add(new Tuple<Vector3, Vector3>(Vector3.Zero, bone1.Translation)); 
lines.Add(new Tuple<Vector3, Vector3>(bone1.Translation, (bone1 *bone2).Translation));

Drawing this onto the screen shows what I expect. The 1st bone is rotated 1 radian around origin, 2nd bone is rotated 2 radians around origin.

I am using the below as reference for parsing and interpreting the BVH data: http://www.dcs.shef.ac.uk/intranet/research/resmes/CS0111.pdf

share|improve this question

1 Answer 1

up vote 0 down vote accepted

I'm not sure how your 3D input data works, but I think your local matrix should be:

 b.localTransform = Matrix.CreateRotationZ(MathHelper.ToRadians(b.z)) * Matrix.CreateRotationY(MathHelper.ToRadians(b.y)) * Matrix.CreateRotationX(MathHelper.ToRadians(b.x)) * Matrix.CreateTranslation(b.Offset);

This is my code for this 2d bone editor:

 //-----------------------------------------------------------------------------------------------------------------------
        public void UpdateLocal( )
        {  
            Vector2 traslation = Translator.GetValue();
            float rotation = Rotator.GetValue();
            Vector2 scale = Scalator.GetValue();

            Matrix mTraslation, mRotation, mScale;
            Matrix.CreateTranslation( traslation.X, traslation.Y, 0, out mTraslation );
            Matrix.CreateRotationZ( rotation, out mRotation );
            Matrix.CreateScale(scale.X, scale.Y, 1 , out mScale );
            Matrix.Multiply( ref mScale, ref mRotation, out Local );
            Matrix.Multiply( ref Local, ref mTraslation, out Local );  
        }

        //-----------------------------------------------------------------------------------------------------------------------
        public virtual void UpdateTransformTopToDown( )
        {
            global_counter++;
            SpecialUpdateTransformTopToDown( );
        }

        //-----------------------------------------------------------------------------------------------------------------------
        protected virtual void SpecialUpdateTransformTopToDown( )
        {
            if ( counter == global_counter ) return;

            counter = global_counter;

            UpdateLocal( );

            if ( Parent != null )
            {
                 Matrix.Multiply( ref Local, ref (Parent as BoneData).Absolute, out Absolute );
            }
            else
            {
                Absolute = Local;
            }

            foreach ( BoneData child in _children.OfType<BoneData>() )
            {
                child.SpecialUpdateTransformTopToDown( );
            }
        }

And this is my code to animate Warcraft3 models, (based in MagosX War3ModelEditor code):

public void BuildTransformMatrix(Intervalo Time, Camara Camara)
    {

        Vector3 TranslationVector;
        Vector4 RotationVector;
        Vector3 ScalingVector;

        TranslationVector = Translation.GetValue(Time);
        RotationVector = Rotation.GetValue(Time);
        ScalingVector = Scaling.GetValue(Time);

        Matrix mPivotPoint = Matrix.CreateTranslation(PivotPoint);
        Matrix mScaling = Matrix.CreateScale(ScalingVector);
        Matrix mRotation = Matrix.CreateFromQuaternion(RotationVector.ToQuaternion());
        Matrix mTranslation = Matrix.CreateTranslation(TranslationVector);

        Matrix mPivotPointInverse = Matrix.Invert(mPivotPoint);


        Transform = mPivotPointInverse * mScaling * mRotation * mPivotPoint * mTranslation;           

        if (Parent != null && Parent.NodeId != -1)
        {
            Transform = Matrix.Multiply(Transform, Parent.Transform);
        }

        foreach (BaseNode child in Children)
        {
            child.BuildTransformMatrix(Time, Camara);
        }
    }
share|improve this answer
    
Thanks for the answer, changing the order of matrix transforms solved the problem. My knowledge of the coordinate systems is a bit shaky, is there a good reference which explains why the orders are switched around when changing from right hand to left hand? All the XNA tutorials I have seen say that XNA is a right hand system, got me quite confused. –  Jkh2 Jan 27 '12 at 16:47
    
Uupps, maybe Xna is right hand, but then opengl is left hand ... :), I reached that conclusion related to the matrix order and the system coordinates by myself, but maybe I'm wrong. May be this question is a good one to ask in gamedev. –  Blau Jan 27 '12 at 21:07
    
I have removed the reference to the order because I'm not sure is right. –  Blau Jan 27 '12 at 21:09
    
I found out that the default coord system in OpenGL and XNA is right-handed. DirectX uses Left handed by default –  Jkh2 Jan 28 '12 at 14:38
    
I think the confusion is that left vs right is not related to the coordinate system, it is related to matrix multiplication order. –  Blau Jan 29 '12 at 18:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.