Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Custom / Script driven skeletal animation?

Discussion in 'Animation' started by xexuxjy, Jan 22, 2016.

  1. xexuxjy

    xexuxjy

    Joined:
    Feb 10, 2014
    Posts:
    18
    Is it possible to correctly play animations by setting the localPosition and localRotation values on transforms directly?
    I've basically got a custom animation format that for an given update will give me the local translation and rotation for each bone used in that animation. I then want to use that information to animate the skeleton correctly.

    What I do at the moment is :
    Store the bind pose localTranslation and localRotation for each transform object in the skeleton.
    On an animation update take the current values for a given bone and use that and the bind pose info to update the local transform/rotation on the node :

    Code (CSharp):
    1. public class BoneAnimData
    2. {
    3.     public BoneAnimData(string name, Transform t)
    4.     {
    5.         boneName = name;
    6.         gameObjectTranform = t;
    7.         bindPoseMatrix = Matrix4x4.TRS(t.localPosition, t.localRotation, Vector3.one);
    8.     }
    9.  
    10.     public void ApplyCurrent()
    11.     {
    12.         currentMatrix = Matrix4x4.TRS(currentPosition, currentRotation, Vector3.one);
    13.         currentMatrix = bindPoseMatrix * currentMatrix;
    14.         //currentMatrix = currentMatrix * bindPoseMatrix;
    15.  
    16.         Vector3 tempPos = new Vector3();
    17.         Quaternion tempRot = new Quaternion();
    18.         Common.DecomposeMatrix(ref currentMatrix, ref tempPos, ref tempRot);
    19.         gameObjectTranform.localPosition = tempPos;
    20.         gameObjectTranform.localRotation = tempRot;
    21.     }
    22.  
    23.     public String boneName;
    24.     public Matrix4x4 bindPoseMatrix;
    25.     public Transform gameObjectTranform;
    26.     //public Vector3 bindPosePosition;
    27.     //public Quaternion bindPoseRotation;
    28.     public Vector3 currentPosition;
    29.     public Quaternion currentRotation = Quaternion.identity;
    30.     public Matrix4x4 currentMatrix = Matrix4x4.identity;
    31. }
    32.  
    33.  public void DoAnimation()
    34.     {
    35.         if (m_currentAnimation != null)
    36.         {
    37.             m_currentAnimation.AnimateTracks(this);
    38.  
    39.             foreach (BoneAnimData bad in m_orderedBoneList)
    40.             {
    41.                 bad.ApplyCurrent();
    42.             }
    43.  
    44.             if (m_currentAnimation.mAnimTime > m_currentAnimation.TrueLength())
    45.             {
    46.                 m_currentAnimation.Reset();
    47.             }
    48.  
    49.         }
    50.     }
    51.  
    52.  
    This seems to work when there is only a very simple hierarchy (2 or 3 transforms) but falls down on my usual skeletons which have about 200 bones (e.g. hip rotations seem to end up with the characters feet and legs and so on rotating as well).

    Is this sort of direct driving of transforms via their local properties a valid way of animating the character, I feel it must be but I'm also sure I've missed an obvious step thats causing all my bad animation.

    Thanks,
     
  2. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,033
    I did something similar recently with my cloth simulation.
    It become quite complex easily because if you have bones parented to each other, when you move the parent you are also moving all the childs and the local position and local rotation are relative to the new calculated position.

    Maybe you aren't taking into account this factor?
     
  3. xexuxjy

    xexuxjy

    Joined:
    Feb 10, 2014
    Posts:
    18
    Thanks, still working through this. Have tried calculating and storing everything off from root down and then applying it at the end to see if that helped. Tried bringing everything into world space , which is what I had code wise in a custom animation viewer but again things just seem to get 'close' to working but ending up with bad results.
    What did you have to do with your cloth simulation to get those nodes working correctly?
    Thanks.
     
  4. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,033
    My case was a bit different.
    I have the cloth simulation which is in world space, but each simulated bone doesn't have any information about rotation.
    So I stored the initial position of the bones, each time I calculated the offset from this initial position and calculate a rotation which rotate the child from the initial position to the new position.
    Initially I was simply making look rotation from the parent to the child, but then when I had to rotate the bone hierarchy outside the simulation( for example the character wearing the cloth was rotating) it become too complex to handle.
    So I let unity do its math and I apply my simulation over the Unity result.
    After I set the rotation,I set again the position of the bones, to have the correct local position again.
    It's important to start from the root bone and go way down to the childern, or you won't be able to set rotation and local position correcly.


    I had a better look at your code.
    I am not very fond of matrices so I can't help much, but are you sure you need to multiply for the current matrix everytime?
    Do you really need bind pose?It's useful for skinning, but in your case I don't see much use.
    You can do it like this:
    1-When saving the animation, store the TRS matrix. That's already the local position and rotation.
    2.When playing back the animation on each frame apply the saved TRS matrix, or an interpolation between the 2 saved frames if you need more frames than you saved.
    3. If you need to move the character, apply the local translation and rotation only on the root bone and the rest will automatically follow.
     
  5. xexuxjy

    xexuxjy

    Joined:
    Feb 10, 2014
    Posts:
    18
    <Sigh> in the end this turned out to be the fact that Unity and XNA / Monogame store data in a Quaternion in a different order and so my original xna code wasn't working as such. I went through all sorts of attempts including building my own animation curves and clips but they all had the same fundamental error. Fixed that and all the techniques I tried worked.
    Simplest one is / was just setting the localPosition and localRotation on the transforms as I'd tried originally.
    Thanks again for peoples help
     
    theANMATOR2b likes this.