How to modify MecAnim Bones Motion

I have a motion capture device (Xsens) that streams live motion data into Unity through a plug-in, and therefore animates a Unity character.

I would like to be able to dampen some movements, exaggerate some, mirror/mimic some, etc…

Is it possible to programmatically modify what will be applied to MecAnim bones? If yes, where do I start? Where do I learn about the internal operations of MecAnim?

There are a lot of tutorials, but mainly to do with applying animations, so I would appreciate any tip son how to start off…

Eventually, I want to have 2 identical characters in Unity, both receiving the same motion data, but I wanna modify one’s script so that it can respond to the other. So, instead of both moving in the same manner (i.e. mirroring/mimicking) I want one to respond with a different limb.

For example, if one character is raising its left arm, the other one raises its right foot. I don’t know if it is possible to do this – maybe the motion that is applied to a hand cannot be applied to a foot, due to different topology or bone structures. This is why I would like to learn about how MecAnim actually works inside, so I can achieve what I have in mind…

You can modify the movement of bones coming from the animation system.

Apply your own modifications in LateUpdate simply by setting the transform values, such as transform.localRotation.

Also see this post: Animation override procedural animation - Questions & Answers - Unity Discussions

1 Like

@runevision Thank you. I am now writing code to modify the bone movements in LateUpdate.

void LateUpdate()
{
    updateLimb(Transform[] pose, Transform[] model);
}

Essentially, update my Unity model with the latest position and orientations (that comprise a pose for a character) and here is how I get the latest:

void Update()
{   
    Vector3[] latestPositions;
    Quaternion[] latestOrientations;

    if (Actors.getLatestPose(out latestPositions, out latestOrientations))
    {             
            updateActor(currentPose, latestPositions, latestOrientations);
            updateModel(currentPose, targetModel);
    }
}

But one more question: Let’s say I wanna apply the animation that moves the left hand to the right hand, so basically I need to swap the latest positions and orientations of the left & right hands. Do I only do this, or do I also need to swap the MecAnim bones that I map beforehand?
This is what I am referring to:

public enum XsAnimationSegment
{
            Pelvis = 0, // Hips
          
            RightUpperLeg = 1,
            RightLowerLeg = 2,
            RightFoot = 3,
            RightToe = 4,
          
            LeftUpperLeg = 5,
            LeftLowerLeg = 6,
            LeftFoot = 7,
            LeftToe = 8,
          
            L5 = 9,
            L3 = 10,    // Spine
            T12 = 11,
            T8 = 12,    // Chest
          
            LeftShoulder = 13,
            LeftUpperArm = 14,
            LeftLowerArm = 15,
            LeftHand = 16,
          
            RightShoulder = 17,
            RightUpperArm = 18,
            RightLowerArm = 19,
            RightHand = 20,
          
            Neck = 21,
            Head = 22
}

int[] segmentOrder =
{
    (int)XsAnimationSegment.Pelvis,
    (int)XsAnimationSegment.RightUpperLeg,
    (int)XsAnimationSegment.RightLowerLeg,
    (int)XsAnimationSegment.RightFoot,
    (int)XsAnimationSegment.RightToe,

    (int)XsAnimationSegment.LeftUpperLeg,
    (int)XsAnimationSegment.LeftLowerLeg,
    (int)XsAnimationSegment.LeftFoot,
    (int)XsAnimationSegment.LeftToe,
          
    (int)XsAnimationSegment.L5,
    (int)XsAnimationSegment.L3,
    (int)XsAnimationSegment.T12,
    (int)XsAnimationSegment.T8,
          
    (int)XsAnimationSegment.LeftShoulder,
    (int)XsAnimationSegment.LeftUpperArm,
    (int)XsAnimationSegment.LeftLowerArm,
    (int)XsAnimationSegment.LeftHand,
                  
    (int)XsAnimationSegment.RightShoulder,
    (int)XsAnimationSegment.RightUpperArm,
    (int)XsAnimationSegment.RightLowerArm,
    (int)XsAnimationSegment.RightHand,

    (int)XsAnimationSegment.Neck,
    (int)XsAnimationSegment.Head
        };

protected void mapMecanimBones()
{
            mecanimBones = new Dictionary<XsAnimationSegment, HumanBodyBones>();

            mecanimBones.Add(XsAnimationSegment.Pelvis,         HumanBodyBones.Hips);
            mecanimBones.Add(XsAnimationSegment.LeftUpperLeg,   HumanBodyBones.LeftUpperLeg);
            mecanimBones.Add(XsAnimationSegment.LeftLowerLeg,   HumanBodyBones.LeftLowerLeg);
            mecanimBones.Add(XsAnimationSegment.LeftFoot,       HumanBodyBones.LeftFoot);
            mecanimBones.Add(XsAnimationSegment.LeftToe,        HumanBodyBones.LeftToes);
            mecanimBones.Add(XsAnimationSegment.RightUpperLeg,  HumanBodyBones.RightUpperLeg);
            mecanimBones.Add(XsAnimationSegment.RightLowerLeg,  HumanBodyBones.RightLowerLeg);
            mecanimBones.Add(XsAnimationSegment.RightFoot,      HumanBodyBones.RightFoot);
            mecanimBones.Add(XsAnimationSegment.RightToe,       HumanBodyBones.RightToes);
            mecanimBones.Add(XsAnimationSegment.L5,             HumanBodyBones.LastBone);
            mecanimBones.Add(XsAnimationSegment.L3,             HumanBodyBones.Spine);
            mecanimBones.Add(XsAnimationSegment.T12,            HumanBodyBones.LastBone);
            mecanimBones.Add(XsAnimationSegment.T8,             HumanBodyBones.Chest);
            mecanimBones.Add(XsAnimationSegment.LeftShoulder,   HumanBodyBones.LeftShoulder);
            mecanimBones.Add(XsAnimationSegment.LeftUpperArm,   HumanBodyBones.LeftUpperArm);
            mecanimBones.Add(XsAnimationSegment.LeftLowerArm,   HumanBodyBones.LeftLowerArm);
            mecanimBones.Add(XsAnimationSegment.LeftHand,       HumanBodyBones.LeftHand);
            mecanimBones.Add(XsAnimationSegment.RightShoulder,  HumanBodyBones.RightShoulder);
            mecanimBones.Add(XsAnimationSegment.RightUpperArm,  HumanBodyBones.RightUpperArm);
            mecanimBones.Add(XsAnimationSegment.RightLowerArm,  HumanBodyBones.RightLowerArm);
            mecanimBones.Add(XsAnimationSegment.RightHand,      HumanBodyBones.RightHand);
            mecanimBones.Add(XsAnimationSegment.Neck,           HumanBodyBones.Neck);
            mecanimBones.Add(XsAnimationSegment.Head,           HumanBodyBones.Head);
}

public bool setupActor()
{
            Actor.position = transform.position;
            Actor.rotation = transform.rotation;

            currentPose[(int)XsAnimationSegment.Pelvis] = Actor.Find("Pelvis");
            currentPose[(int)XsAnimationSegment.L5] = Actor.Find("Pelvis/L5");
            currentPose[(int)XsAnimationSegment.L3] = Actor.Find("Pelvis/L5/L3");
            currentPose[(int)XsAnimationSegment.T12] = Actor.Find("Pelvis/L5/L3/T12");
            currentPose[(int)XsAnimationSegment.T8] = Actor.Find("Pelvis/L5/L3/T12/T8");

            currentPose[(int)XsAnimationSegment.LeftShoulder] = Actor.Find("Pelvis/L5/L3/T12/T8/LeftShoulder");
            currentPose[(int)XsAnimationSegment.LeftUpperArm] = Actor.Find("Pelvis/L5/L3/T12/T8/LeftShoulder/LeftUpperArm");
            currentPose[(int)XsAnimationSegment.LeftLowerArm] = Actor.Find("Pelvis/L5/L3/T12/T8/LeftShoulder/LeftUpperArm/LeftLowerArm");
            currentPose[(int)XsAnimationSegment.LeftHand] = Actor.Find("Pelvis/L5/L3/T12/T8/LeftShoulder/LeftUpperArm/LeftLowerArm/LeftHand");

            currentPose[(int)XsAnimationSegment.Neck] = Actor.Find("Pelvis/L5/L3/T12/T8/Neck");
            currentPose[(int)XsAnimationSegment.Head] = Actor.Find("Pelvis/L5/L3/T12/T8/Neck/Head");

            currentPose[(int)XsAnimationSegment.RightShoulder] = Actor.Find("Pelvis/L5/L3/T12/T8/RightShoulder");
            currentPose[(int)XsAnimationSegment.RightUpperArm] = Actor.Find("Pelvis/L5/L3/T12/T8/RightShoulder/RightUpperArm");
            currentPose[(int)XsAnimationSegment.RightLowerArm] = Actor.Find("Pelvis/L5/L3/T12/T8/RightShoulder/RightUpperArm/RightLowerArm");
            currentPose[(int)XsAnimationSegment.RightHand] = Actor.Find("Pelvis/L5/L3/T12/T8/RightShoulder/RightUpperArm/RightLowerArm/RightHand");

            currentPose[(int)XsAnimationSegment.LeftUpperLeg] = Actor.Find("Pelvis/LeftUpperLeg");
            currentPose[(int)XsAnimationSegment.LeftLowerLeg] = Actor.Find("Pelvis/LeftUpperLeg/LeftLowerLeg");
            currentPose[(int)XsAnimationSegment.LeftFoot] = Actor.Find("Pelvis/LeftUpperLeg/LeftLowerLeg/LeftFoot");
            currentPose[(int)XsAnimationSegment.LeftToe] = Actor.Find("Pelvis/LeftUpperLeg/LeftLowerLeg/LeftFoot/LeftToe");

            currentPose[(int)XsAnimationSegment.RightUpperLeg] = Actor.Find("Pelvis/RightUpperLeg");
            currentPose[(int)XsAnimationSegment.RightLowerLeg] = Actor.Find("Pelvis/RightUpperLeg/RightLowerLeg");
            currentPose[(int)XsAnimationSegment.RightFoot] = Actor.Find("Pelvis/RightUpperLeg/RightLowerLeg/RightFoot");
            currentPose[(int)XsAnimationSegment.RightToe] = Actor.Find("Pelvis/RightUpperLeg/RightLowerLeg/RightFoot/RightToe");

            // Re-set the pelvis TP.
            pelvisPosTP = currentPose[(int)XsAnimationSegment.Pelvis].position;

            return true;
}

Sorry, I don’t know anything about that. I pinged out animation developers and sent them a link to this thread.

1 Like

Thanks for your attention and help. I look forward to hearing from them…