Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. We're looking for your feedback on the platforms you use and how you use them. Let us know!
    Dismiss Notice
  4. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  6. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  7. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  8. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Recording Humanoid Animations with Foot IK

Discussion in 'Animation' started by jacques_f, Aug 13, 2018 at 5:51 AM.

  1. jacques_f

    jacques_f

    Joined:
    Jan 17, 2018
    Posts:
    2
    I am attempting to set up a humanoid animation recorder to save animations from a motion capture system within Unity. I have successfully set up the recorder so that it can save animation clips with all the muscle space data, but am running into problems with foot IK. Every time I have tried recording the feet position/orientation in muscle space the results are not what I expect (wrong position, wrong orientation, etc...). Disabling foot-ik on the animation fixes the issue, but means it cannot be used with timeline (since timeline appears to force foot-ik on).

    The only information I've been able to find regarding encoding the feet positions and orientations is from this Unity blog post: https://blogs.unity3d.com/2014/05/26/mecanim-humanoids/
    In that post it says "The hands and feet position and orientation are normalized relative to Humanoid Root (center of mass, average body rotation and humanoid scale) in the Muscle Space."

    I've tried recording the feet positions and orientations relative to the Animator bodyPosition and bodyRotation without success. I've also attempted recording relative to the root transform of the body. So I'm reaching out to see if anyone has found any further documentation regarding how the feet position and orientation is transformed to make it normalized relative to Humanoid Root. Ideally I’d really appreciate a short example script that shows a transform for the position/orientation of a foot being normalized relative to humanoid root in the muscle space, but any help is much appreciated.
     
  2. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,573
    Hi @jacques_f

    take a look at this script, it should give you all the info to compute the hands and feet position relative to animator body position and rotation.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using System;
    6. using System.Reflection;
    7. public class TQ
    8. {
    9.     public TQ(Vector3 translation, Quaternion rotation)
    10.     {
    11.         t = translation;
    12.         q = rotation;
    13.     }
    14.     public Vector3 t;
    15.     public Quaternion q;
    16.     // Scale should always be 1,1,1
    17. }
    18. public class AvatarUtility {
    19.     static public TQ GetIKGoalTQ(Avatar avatar, float humanScale, AvatarIKGoal avatarIKGoal, TQ animatorBodyPositionRotation, TQ skeletonTQ)
    20.     {
    21.         int humanId = (int)HumanIDFromAvatarIKGoal(avatarIKGoal);
    22.         if(humanId == (int)HumanBodyBones.LastBone)
    23.             throw new InvalidOperationException("Invalid human id.");
    24.         MethodInfo methodGetAxisLength = typeof(Avatar).GetMethod("GetAxisLength", BindingFlags.Instance | BindingFlags.NonPublic);
    25.         if(methodGetAxisLength == null)
    26.             throw new InvalidOperationException("Cannot find GetAxisLength method.");
    27.         MethodInfo methodGetPostRotation = typeof(Avatar).GetMethod("GetPostRotation", BindingFlags.Instance | BindingFlags.NonPublic);
    28.         if(methodGetPostRotation == null)
    29.             throw new InvalidOperationException("Cannot find GetPostRotation method.");
    30.         Quaternion postRotation = (Quaternion)methodGetPostRotation.Invoke(avatar, new object[]{humanId});
    31.         var goalTQ = new TQ(skeletonTQ.t, skeletonTQ.q * postRotation);
    32.         if(avatarIKGoal == AvatarIKGoal.LeftFoot || avatarIKGoal == AvatarIKGoal.RightFoot)
    33.         {
    34.             // Here you could use animator.leftFeetBottomHeight or animator.rightFeetBottomHeight rather than GetAxisLenght
    35.             // Both are equivalent but GetAxisLength is the generic way and work for all human bone
    36.             float axislength = (float) methodGetAxisLength.Invoke(avatar, new object[]{humanId});
    37.             Vector3 footBottom = new Vector3(axislength, 0, 0);
    38.             goalTQ.t += (goalTQ.q * footBottom);
    39.         }
    40.         // IK goal are in avatar body local space
    41.         Quaternion invRootQ = Quaternion.Inverse(animatorBodyPositionRotation.q);
    42.         goalTQ.t = invRootQ * (goalTQ.t - animatorBodyPositionRotation.t);
    43.         goalTQ.q = invRootQ * goalTQ.q;
    44.         goalTQ.t /= humanScale;
    45.      
    46.         return goalTQ;
    47.     }
    48.     static public HumanBodyBones HumanIDFromAvatarIKGoal(AvatarIKGoal avatarIKGoal)
    49.     {
    50.         HumanBodyBones humanId = HumanBodyBones.LastBone;
    51.         switch(avatarIKGoal)
    52.         {
    53.             case AvatarIKGoal.LeftFoot: humanId = HumanBodyBones.LeftFoot; break;
    54.             case AvatarIKGoal.RightFoot: humanId = HumanBodyBones.RightFoot; break;
    55.             case AvatarIKGoal.LeftHand: humanId = HumanBodyBones.LeftHand; break;
    56.             case AvatarIKGoal.RightHand: humanId = HumanBodyBones.RightHand; break;
    57.         }
    58.         return humanId;
    59.     }
    60. }