Search Unity

  1. We are looking for feedback on the experimental Unity Safe Mode which is aiming to help you resolve compilation errors faster during project startup.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

How can I override scale using Animation Rigging?

Discussion in 'Animation Previews' started by Ruberta, Nov 1, 2019.

  1. Ruberta


    Mar 5, 2019
    I want to manipulate scale of bone such as increasing character leg length for character customization. How can I do this with new animation rigging?

    If I directly scale character leg bone, foot is not lock at root level anymore.
  2. Ruberta


    Mar 5, 2019
    This is what it happen when directly scale character leg bone with ninja model. And here is a code in lateUpdate.

    Code (CSharp):
    2.         void LateUpdate()
    3.         {
    4.             foreach (PData _data in data)
    5.             {
    6.                 _data.bone.transform.localScale = _data.scale;
    7.             }
    8.         }
    I want to lock bone at the root level but have no idea how to get that.
  3. davehunt_unity


    Unity Technologies

    Nov 13, 2017
    Hi Ruberta,

    Thanks for your questions about scale. I can explain a bit more about what's going on here...

    There are known limitations with how non-uniform scale currently works in Unity with regard to skeletal animation. There are artifacts with shearing that happen when using non-uniform scale (for example, only the X axis) on animated bones that have animated child bones. Since this limitation exists with the underlying animation system, this is why it is out of scope for the Animation Rigging package to attempt to solve this.

    If squash and stretch animation is the desired effect there are ways to do this in your rigging setups using leaf-node bones that have no animated child bones. I can explain more about this if that's the way you want to go. However, from your description it sounds like you are attempting to do something different with static variations of character proportions. I am hopeful that we will be able to support this in the future, but at this time I can't make any guarantees.

    The type of animated scale that is supported by Animation Rigging is: object-level uniform scale. This is where you can scale the top game object evenly on all axes at once to make variations in overall size. If you encounter issues with Animation Rigging in this area please submit a bug report because we intend for that to work and will attempt to fix those bugs.

    I hope that explanation helps and let me know if there are any further questions I can help with.
    Ruberta likes this.
  4. Ruberta


    Mar 5, 2019
    Thank you for reply. I make system for character customization. I have solution for myself now. Instead of scale the leg bone, I adjust position of upper leg bone and pelvis. This way the foot will not move away from the root. Then I can scale only y and z if I want the leg bigger a little bit.
  5. theazz


    Oct 20, 2013
    Hey @davehunt_unity - thanks for clearing this up, I've been looking into the non uniform scale stuff for a while and getting nowhere. I'd love to ask a couple of questions if that's OK?

    Is there any plans to change this at all? Is there any other way to get parity with Maya Segment scale compensate on a traditional skeleton or is a flat hiearchy / leaf joints on a traditional skeleton the only way you think?

  6. davehunt_unity


    Unity Technologies

    Nov 13, 2017
    Hi theazzz,

    In response to your question above, these are some of the things that will be possible with the new DOTS Animation architecture. We are aware of the need from user requests such as this (and from myself!) and we are currently working on the foundation that will make it possible. I'm not able to make any specific statements about when it will be available, but just to reassure you we have heard the request and we are taking it into account.

    theazz likes this.
  7. Virtualware


    Sep 17, 2012
    Hi @davehunt_unity !!

    We've been getting into this new animation rigging package lately and we have some problems about scale transformations as mentioned above.

    Doing some tests we've discovered that the Two Bone IK constraint doesn't perform correctly when scaling the animation root, even it's a proportional scale.

    Isn't this supposed to be supported?

  8. simonbz


    Unity Technologies

    Sep 28, 2015
    TwoBoneIK will work with different uniform root scale values.


    How did you setup your character rig? Maybe some other constraints are preventing your Two Bone IK to work when its scale value changes.
  9. Virtualware


    Sep 17, 2012
    Hello @simonbz and thank you for your quick reply!

    We've made several tests using only the Two Bone IK constraint to avoid other interactions and the problem persists... The character rig setup has been done following the package guide and we are scaling a parent object of the whole rig system.

    After seeing your screenshot I made further investigation and I achieved an important conclusion: Uniform scaling do work only if it's made before pressing the play button. It won't work if you try to scale the rig on runtime.

    I guess that constraints calculate some initial data on startup and maybe are not prepared for further scales beyond that point.

    Our current requirements are to scale the rig during runtime, so it would be great if you could help us on this.

    Thank you very much!
  10. Jebtor


    Unity Technologies

    Apr 18, 2018
    Hey Virtualware,

    Thanks for pointing this out! You are right. When entering playmode the TwoBoneIKConstraintJob is created, as an optimization we are storing the lengths of the bones during creation. So that the run-time algorithm does not have to calculate the bone lengths every frame. This of course assumes that the bone lengths do not change at runtime. Which is not a valid assumption if the scaling changes during runtime...

    I can offer you two solutions that you can try to work around this limitation straight away. You can either rebuild the Rig when scaling is applied, this will recreate the job with the new bone lengths. You can force a rebuild of a rig through code by calling RigBuilder.Build() on a rig. Rebuilding, however, can become quite costly... And thus I would strongly recommend looking into my next proposed solution.
    Namely. modifying or creating a custom version of the TwoBoneIKConstraint inside your project. Inside the animation rigging package in Runtime/AnimationJobs/TwoBoneIKConstriantJob.cs you will find the code for the TwoBoneIKConstriant. You can duplicate this code into your project to create a custom version of the constraint or modify the code there if the package is embedded locally. In both cases you will want to modify ProcessAnimation to do something like this:

    Code (CSharp):
    1.        public void ProcessAnimation(AnimationStream stream)
    2.         {
    3.             float w = jobWeight.Get(stream);
    4.             if (w > 0f)
    5.             {
    6.                 // Use Tip, Mid and Root handles to get bone positions
    7.                 // Recompute bone lengths
    8.                 // Use the recomputed lengths for the solve call below
    9.                 AnimationRuntimeUtils.SolveTwoBoneIK(
    10.                     stream, root, mid, tip, target, hint,
    11.                     targetPositionWeight.Get(stream) * w,
    12.                     targetRotationWeight.Get(stream) * w,
    13.                     hintWeight.Get(stream) * w,
    14.                     linkLengths,
    15.                     targetOffset
    16.                     );
    17.             }
    18.             else
    19.             {
    20.                 AnimationRuntimeUtils.PassThrough(stream, root);
    21.                 AnimationRuntimeUtils.PassThrough(stream, mid);
    22.                 AnimationRuntimeUtils.PassThrough(stream, tip);
    23.             }
    24.         }
    25.     }
    Please have a look at this Unite talk for more information on writing custom constraints:

    I apologize that the only solutions that will help you straight away requires coding. I will bring this case up with the team and see if we want to reconsider our optimization here. I hope this helps!
  11. Jebtor


    Unity Technologies

    Apr 18, 2018
    We had a look at the implementation and decided to modify the constraint to support dynamic limb lengths. The next version of the package should support your use case out of the box. Thanks for bringing this to our attention
  12. Virtualware


    Sep 17, 2012
    Hello @Jebtor and thank you very much for your quick and detailed response!!

    We're glad to hear that dynamic limb lengths are going to come out of the box with the next package release :)

    Meanwhile, we have implemented our own TwoBoneIKConstraint to fix it. It's been very easy since we already had implemented a few custom made constraints for this project.

    Thank you again for the good support!
  13. keenanwoodall


    May 30, 2014
    I'm scaling a rig builder object uniformly at runtime and the Two Bone IK Constraint does not seem work correctly. I'm looking at where the IK target is positioned and it is correct. Has dynamic limb lengths made it into a released version yet?
  14. Jebtor


    Unity Technologies

    Apr 18, 2018
    Yes it did :)

    In the changelog you can see it should be fixed from 0.3.3 on wards. Please reach out if you still encounter problems, any extra information will be helpful.
  15. keenanwoodall


    May 30, 2014
    @Jebtor I'm working on an "avatar" system for VR. The idea is that you have a source avatar that tracks the head/hands. You can add other avatars that have their hands/head follow the hands head of the source avatar using a script I wrote called XRAvatarBinder. You assign the source head/head transforms and target head/hand transforms to the script and it updates the target transforms to have the same position/rotation. There's some extra math to make all the calculations relative to each avatars parent container to allow moving an avatar separately from the source.

    Here's the script if anyone needs it
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    4. [DefaultExecutionOrder(1)]
    5. public class XRAvatarBinder : MonoBehaviour
    6. {
    7.     // A utility class to make converting between avatar spaces easier
    8.     public class BindSpace
    9.     {
    10.         public Transform targetContainer { get; private set; }
    11.         public Transform sourceContainer { get; private set; }
    13.         public BindSpace(Transform targetContainer, Transform sourceContainer)
    14.         {
    15.             this.targetContainer = targetContainer;
    16.             this.sourceContainer = sourceContainer;
    17.         }
    19.         public Vector3 WorldSourceToWorldTargetPoint(Vector3 worldSourcePoint)
    20.         {
    21.             return LocalSourceToWorldTargetPoint(sourceContainer.InverseTransformPoint(worldSourcePoint));
    22.         }
    24.         public Vector3 LocalSourceToWorldTargetPoint(Vector3 localSourcePoint)
    25.         {
    26.             return targetContainer.TransformPoint(localSourcePoint);
    27.         }
    28.         public Vector3 WorldSourceToWorldTargetDirection(Vector3 worldSourceDirection)
    29.         {
    30.             return targetContainer.TransformDirection(sourceContainer.InverseTransformDirection(worldSourceDirection));
    31.         }
    33.         public Quaternion WorldSourceToWorldTargetRotation(Quaternion worldSourceRotation)
    34.         {
    35.             return targetContainer.rotation * Quaternion.Inverse(sourceContainer.rotation) * worldSourceRotation;
    36.         }
    37.     }
    39.     [Serializable]
    40.     public class Binding
    41.     {
    42.         public Transform source;
    43.         public Transform target;
    45.         public Vector3 positionOffset;
    46.         public Vector3 rotationOffset;
    48.         public virtual void Bind(BindSpace bindSpace)
    49.         {
    50.             Vector3 position = bindSpace.WorldSourceToWorldTargetPoint(source.TransformPoint(positionOffset));
    51.             Quaternion rotation = bindSpace.WorldSourceToWorldTargetRotation(source.rotation * Quaternion.Euler(rotationOffset));
    53.             target.SetPositionAndRotation(position, rotation);
    54.         }
    56.         public virtual bool IsValid() => source != null && target != null;
    58.         public bool TryBind(BindSpace bindSpace)
    59.         {
    60.             bool isValid = IsValid();
    61.             if (isValid)
    62.                 Bind(bindSpace);
    63.             return isValid;
    64.         }
    65.     }
    67.     [Serializable]
    68.     public class BodyBinding : Binding
    69.     {
    70.         public float rotationSpeed = 3f;
    72.         public override void Bind(BindSpace bindSpace) => Bind(bindSpace, Time.deltaTime);
    73.         public void Bind(BindSpace bindSpace, float deltaTime)
    74.         {
    75.             Vector3 position = bindSpace.LocalSourceToWorldTargetPoint(bindSpace.sourceContainer.InverseTransformPoint(source.position) + positionOffset);
    76.             Vector3 direction = bindSpace.WorldSourceToWorldTargetDirection(source.forward);
    77.             direction = bindSpace.targetContainer.InverseTransformDirection(direction);
    78.             direction.y = 0f;
    79.             direction = bindSpace.targetContainer.TransformDirection(direction);
    81.             Quaternion targetRotation = Quaternion.LookRotation(direction, bindSpace.targetContainer.up) * Quaternion.Euler(rotationOffset);
    82.             Quaternion rotation = Quaternion.Lerp(target.rotation, targetRotation, rotationSpeed * deltaTime);
    84.             target.SetPositionAndRotation(position, rotation);
    85.         }
    86.     }
    89.     public Transform sourceContainer;
    90.     public Transform targetContainer;
    91.     public bool bindContainers = true;
    92.     public Binding head, leftHand, rightHand;
    93.     public BodyBinding body;
    95.     private BindSpace bindSpace;
    97.     private void Start()
    98.     {
    99.         if (sourceContainer == null)
    100.         {
    101.             sourceContainer = transform;
    102.         }
    104.         if (targetContainer == null)
    105.         {
    106.             targetContainer = transform;
    107.         }
    109.         bindSpace = new BindSpace(targetContainer, sourceContainer);
    110.     }
    112.     private void LateUpdate()
    113.     {
    114.         if (bindContainers)
    115.         {
    116.             if (sourceContainer != null && targetContainer != null)
    117.             {
    118.                 targetContainer.SetPositionAndRotation(sourceContainer.position, sourceContainer.rotation);
    120.                 Vector3 sourceScale = sourceContainer.lossyScale;
    122.                 if (targetContainer.parent == null)
    123.                     targetContainer.localScale = sourceScale;
    124.                 else
    125.                     targetContainer.localScale = targetContainer.parent.InverseTransformPoint(targetContainer.parent.rotation * sourceScale);
    126.             }
    127.         }
    128.         head.TryBind(bindSpace);
    129.         leftHand.TryBind(bindSpace);
    130.         rightHand.TryBind(bindSpace);
    131.         body.TryBind(bindSpace);
    132.     }
    133. }

    This makes it easy to setup the different versions of the player required for VR. For example, the "visuals" avatar is just a pair of hands which is only seen by the HMD. We also have a "mirror" avatar which is an entire upper body. This is only seen by external cameras and mirrors. The mirror avatar uses the animation rigging package (preview - 0.2.6) for the arm IK.

    Here's what my hierarchy looks like. You can see there's a Source avatar with head ("HMD") and hands. Then there's a Visuals and Mirror avatar. They both have an XRAvatarBinder component which binds their target transforms to the source transforms.

    The scale of the Visuals and Mirror transform are updated constantly to match the Source transform scale. The Visuals avatar works correctly when scaled since it doesn't use any IK. The Mirror avatar does not work when scaled unless I enable/disable or call Build(). I'm using the XRAvatarBinder to bind the IK target transforms to the source hand transforms. I added gizmo icons to the source and IK target transforms in the following video so you can see they are positioned at exactly the same place. Even though the IK targets are positioned correctly via the XRAvatarBinder, the Two Bone IK Constraint doesn't update the arm joints correctly.

    Here's the video:

    I have both the Visuals and Mirror avatar visible to the game camera for debugging. The white hands are part of the Visuals avatar (positioned correctly) and the blue-ish hands are part of the Mirror avatar which uses the animation rigging package (not positioned correctly). In the video I am gripping both controllers and moving my hands closer/further to scale up/down. It's kinda hard to see the labels in the video, but they flicker because the source/ik target transforms are positioned directly on top of eachother. This is why I was curious if dynamic limb length was working. The IK target is positioned correctly but the arms are not.

    Thanks for working on this awesome package, and let me know if you need any more info!
    Jebtor likes this.
  16. Jebtor


    Unity Technologies

    Apr 18, 2018
    Cool project! The version you are using does not support dynamic link lengths for the two bone IK. Dynamic lengths are supported in 0.3.3+, you mention you are using 0.2.6. To resolve the issues you are seeing you would either have to upgrade to 0.3.3+ or embed the package locally and modify the constraint, as described in my first reply in this thread. Apologies for the inconvenience.
  17. keenanwoodall


    May 30, 2014
    Ah my bad! For some reason the package manager wasn't showing a newer version so I had a brainfart and assumed I was on the version you mentioned. ᵉᵛᵉⁿ ᵗʰᵒᵘᵍʰ ᶦ ˡᶦᵗᵉʳᵃˡˡʸ ᵗʸᵖᵉᵈ ᵒᵘᵗ ᵐʸ ᵒˡᵈᵉʳ ᵛᵉʳˢᶦᵒⁿ ᶦⁿ ᵐʸ ʳᵉˢᵖᵒⁿˢᵉ...ᵒᵒᶠ

    If I don't see the newer version does that mean it's only supported on newer version of Unity (I'm on 2019.3.10), or do I just need to change the version in the manifest manually?

    I tried setting the version to "com.unity.animation.rigging": "0.3.3-preview" manually but got a bunch of errors
  18. Jebtor


    Unity Technologies

    Apr 18, 2018
    Correct, the 0.2.X line is tied to 2019.3, the 0.3.X line on the other hand is linked to 2020.1. The errors you see in the console are things that only exist in Unity 2020.1.
    keenanwoodall likes this.
  19. DrummerB


    Dec 19, 2013
    Is changing the root scale at runtime also supported? I have a very simple setup with some TwoBoneIKConstraints. If I change the root scale at runtime, and then move an IK target, the position of the target seems to be scaled. E.g. if I scale the root to 0.5, the IK systems seems to think the target it at half the distance to the root.

    Code (CSharp):
    1. Root
    2.     Animator, RigBuilder
    3.         SkinnedMeshRenderer
    4.         SkeletonRoot
    5.             ....
    6.         Rig
    7.             TwoBoneIKConstraint
    8.                 Target
    9.                 Hint
  20. giordi91


    Oct 15, 2015
    @Jebtor Any plan to backport this to 2019.3?
  21. Jebtor


    Unity Technologies

    Apr 18, 2018
    Hey, we are not ruling out back porting this back to 19.3. However right now we are focusing on the 2020 release. If you are blocked by this you could modify the constraint locally (there is an explanation in my first post in this thread). I apologize for the inconvenience.