Search Unity

Question SkinnedMeshRenderer animation not applying bindposes/pivot points

Discussion in 'Animation' started by adcimon, Mar 28, 2021.

  1. adcimon

    adcimon

    Joined:
    Aug 8, 2012
    Posts:
    8
    Hi,

    I have a problem importing animations from Warcraft 3 models (I want to do a modding tool with Unity). I used as a reference the Mesh.bindposes documentation.

    This is the model imported with the rig, each bone is a green dot.



    Bindposes are calculated like this:
    Code (CSharp):
    1. mesh.bindposes = bones.Values.Select(go => go.transform.worldToLocalMatrix * skeleton.transform.localToWorldMatrix).ToArray();
    Then root bone and bones are set to the SkinnedMeshRenderer:
    Code (CSharp):
    1. renderer.bones = bones.Values.ToArray().Select(go => go.transform).ToArray();
    2. renderer.rootBone = skeleton.transform;
    Skin weights are also imported properly.

    And then the translations and rotations components of the animations are imported (Y and Z coordinates are swapped):

    Code (CSharp):
    1.    float time = node.Time - csequence.IntervalStart;
    2.    Vector3 position = node.Value.ToVector3();
    3.  
    4.    Keyframe keyX = new Keyframe(time / frameRate, position.x);
    5.    curveX.AddKey(keyX);
    6.  
    7.    Keyframe keyY = new Keyframe(time / frameRate, position.z);
    8.    curveY.AddKey(keyY);
    9.  
    10.    Keyframe keyZ = new Keyframe(time / frameRate, position.y);
    11.    curveZ.AddKey(keyZ);
    12.  
    13.    if( curveX.length > 0 )
    14.        clip.SetCurve(path, typeof(Transform), "localPosition.x", curveX);
    15.    if( curveY.length > 0 )
    16.        clip.SetCurve(path, typeof(Transform), "localPosition.y", curveY);
    17.    if( curveZ.length > 0 )
    18.        clip.SetCurve(path, typeof(Transform), "localPosition.z", curveZ);
    19.  
    Code (CSharp):
    1.     float time = node.Time - csequence.IntervalStart;
    2.     Quaternion rotation = node.Value.ToQuaternion();
    3.  
    4.     Keyframe keyX = new Keyframe(time / frameRate, rotation.x);
    5.     curveX.AddKey(keyX);
    6.  
    7.     Keyframe keyY = new Keyframe(time / frameRate, rotation.z);
    8.     curveY.AddKey(keyY);
    9.  
    10.     Keyframe keyZ = new Keyframe(time / frameRate, rotation.y);
    11.     curveZ.AddKey(keyZ);
    12.  
    13.     Keyframe keyW = new Keyframe(time / frameRate, -rotation.w);
    14.     curveW.AddKey(keyW);
    15.  
    16.    if( curveX.length > 0 )
    17.        clip.SetCurve(path, typeof(Transform), "localRotation.x", curveX);
    18.    if( curveY.length > 0 )
    19.        clip.SetCurve(path, typeof(Transform), "localRotation.y", curveY);
    20.    if( curveZ.length > 0 )
    21.        clip.SetCurve(path, typeof(Transform), "localRotation.z", curveZ);
    22.    if( curveW.length > 0 )
    23.        clip.SetCurve(path, typeof(Transform), "localRotation.w", curveW);

    The animation result is the following:



    The animations looks perfect but it is anchored to the skinned mesh renderer gameobject (0,0,0). It seems that the bindposes or pivot points are not applied when the animation is playing.

    In the example, the Body bone pivot point is (0.6, 50, -0.5) and the local position at that animation keyframe is (0, -5, 0). Also the Rifle bone pivot point is (2.5, -0.5, 4) and the local position at that animation keyframe is (11, 37, -8), the Rifle is higher than the Body (both bones are parented to the Root gameobject).

    Thank you for your time.
     

    Attached Files:

    • 1.png
      1.png
      File size:
      256.8 KB
      Views:
      314
    • 2.png
      2.png
      File size:
      226.9 KB
      Views:
      313
  2. adcimon

    adcimon

    Joined:
    Aug 8, 2012
    Posts:
    8
    I solved the bug adding the local position of the bone to each animation keyframe of the position.

    Code (CSharp):
    1. Vector3 position = bone.transform.localPosition + node.Value.ToVector3().SwapYZ();