Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How can I override scale using Animation Rigging?

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

  1. Ruberta

    Ruberta

    Joined:
    Mar 5, 2019
    Posts:
    114
    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

    Ruberta

    Joined:
    Mar 5, 2019
    Posts:
    114
    upload_2019-11-1_14-37-13.png
    This is what it happen when directly scale character leg bone with ninja model. And here is a code in lateUpdate.

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

    davehunt_unity

    Unity Technologies

    Joined:
    Nov 13, 2017
    Posts:
    32
    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.
     
    colinleet and Ruberta like this.
  4. Ruberta

    Ruberta

    Joined:
    Mar 5, 2019
    Posts:
    114
    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

    theazz

    Joined:
    Oct 20, 2013
    Posts:
    60
    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?

    cheers
     
  6. davehunt_unity

    davehunt_unity

    Unity Technologies

    Joined:
    Nov 13, 2017
    Posts:
    32
    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.

    skål
     
    theazz likes this.
  7. Virtualware

    Virtualware

    Joined:
    Sep 17, 2012
    Posts:
    75
    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?

    Thanks!
     
  8. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,
    TwoBoneIK will work with different uniform root scale values.

    NinjaWithRootScale.png

    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

    Virtualware

    Joined:
    Sep 17, 2012
    Posts:
    75
    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

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    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!
     
    Threeyes likes this.
  11. Jebtor

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    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

    Virtualware

    Joined:
    Sep 17, 2012
    Posts:
    75
    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

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    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

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    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

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    @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;
    3.  
    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; }
    12.  
    13.         public BindSpace(Transform targetContainer, Transform sourceContainer)
    14.         {
    15.             this.targetContainer = targetContainer;
    16.             this.sourceContainer = sourceContainer;
    17.         }
    18.    
    19.         public Vector3 WorldSourceToWorldTargetPoint(Vector3 worldSourcePoint)
    20.         {
    21.             return LocalSourceToWorldTargetPoint(sourceContainer.InverseTransformPoint(worldSourcePoint));
    22.         }
    23.  
    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.         }
    32.  
    33.         public Quaternion WorldSourceToWorldTargetRotation(Quaternion worldSourceRotation)
    34.         {
    35.             return targetContainer.rotation * Quaternion.Inverse(sourceContainer.rotation) * worldSourceRotation;
    36.         }
    37.     }
    38.  
    39.     [Serializable]
    40.     public class Binding
    41.     {
    42.         public Transform source;
    43.         public Transform target;
    44.  
    45.         public Vector3 positionOffset;
    46.         public Vector3 rotationOffset;
    47.    
    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));
    52.        
    53.             target.SetPositionAndRotation(position, rotation);
    54.         }
    55.  
    56.         public virtual bool IsValid() => source != null && target != null;
    57.  
    58.         public bool TryBind(BindSpace bindSpace)
    59.         {
    60.             bool isValid = IsValid();
    61.             if (isValid)
    62.                 Bind(bindSpace);
    63.             return isValid;
    64.         }
    65.     }
    66.  
    67.     [Serializable]
    68.     public class BodyBinding : Binding
    69.     {
    70.         public float rotationSpeed = 3f;
    71.  
    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);
    80.        
    81.             Quaternion targetRotation = Quaternion.LookRotation(direction, bindSpace.targetContainer.up) * Quaternion.Euler(rotationOffset);
    82.             Quaternion rotation = Quaternion.Lerp(target.rotation, targetRotation, rotationSpeed * deltaTime);
    83.  
    84.             target.SetPositionAndRotation(position, rotation);
    85.         }
    86.     }
    87.  
    88.  
    89.     public Transform sourceContainer;
    90.     public Transform targetContainer;
    91.     public bool bindContainers = true;
    92.     public Binding head, leftHand, rightHand;
    93.     public BodyBinding body;
    94.  
    95.     private BindSpace bindSpace;
    96.  
    97.     private void Start()
    98.     {
    99.         if (sourceContainer == null)
    100.         {
    101.             sourceContainer = transform;
    102.         }
    103.  
    104.         if (targetContainer == null)
    105.         {
    106.             targetContainer = transform;
    107.         }
    108.    
    109.         bindSpace = new BindSpace(targetContainer, sourceContainer);
    110.     }
    111.  
    112.     private void LateUpdate()
    113.     {
    114.         if (bindContainers)
    115.         {
    116.             if (sourceContainer != null && targetContainer != null)
    117.             {
    118.                 targetContainer.SetPositionAndRotation(sourceContainer.position, sourceContainer.rotation);
    119.  
    120.                 Vector3 sourceScale = sourceContainer.lossyScale;
    121.  
    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.
    upload_2020-4-20_10-28-44.png

    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

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    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

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    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. ᵉᵛᵉⁿ ᵗʰᵒᵘᵍʰ ᶦ ˡᶦᵗᵉʳᵃˡˡʸ ᵗʸᵖᵉᵈ ᵒᵘᵗ ᵐʸ ᵒˡᵈᵉʳ ᵛᵉʳˢᶦᵒⁿ ᶦⁿ ᵐʸ ʳᵉˢᵖᵒⁿˢᵉ...ᵒᵒᶠ
    upload_2020-4-21_8-7-0.png

    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
    upload_2020-4-21_8-13-48.png
     
  18. Jebtor

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    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

    DrummerB

    Joined:
    Dec 19, 2013
    Posts:
    135
    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

    giordi91

    Joined:
    Oct 15, 2015
    Posts:
    1
    @Jebtor Any plan to backport this to 2019.3?
     
  21. Jebtor

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    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.
     
  22. DanBourquinLHS

    DanBourquinLHS

    Joined:
    Feb 21, 2020
    Posts:
    1
    Maybe I'm doing something wrong but TwoBonesIKConstraint don't handle the new bones length when changing the local scale of a bone at runtime. I use the 0.3.4 version of the package.

    Here's what I did:


    I tried to rebuild the RigBuilder by script too but it wont work neither.
     
    Last edited: Sep 22, 2020
  23. Jebtor

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
  24. danBourquin

    danBourquin

    Joined:
    Nov 16, 2016
    Posts:
    34
    Humanoid animation. Avatar is generated at importation of the Mixamo model. And the animator is only an empty state. Because I don't want to animate my model just to use the IK algorithm to move feet at position. Btw animator's layer is set to IK.
     
  25. Jebtor

    Jebtor

    Unity Technologies

    Joined:
    Apr 18, 2018
    Posts:
    113
    So I suspect this will work with a Generic avatar. I don't think you are supposed to scale humanoid bones, especially at runtime. Overall scaling of bones inside the hierarchy can become very tricky. I am not sure about your use case but you could for example also change the local position to make a bone longer.
     
    DanBourquinLHS likes this.
  26. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80
    Hi, I have been using DampTransform with the version 1.0.3, and model shrink when I uniform scale it. Use Damp.unity scene as example, Here is the origin scale:

    微信截图_20210628172019.png

    And here we scale 5 times:
    upload_2021-6-28_17-21-26.png
     
    bearcoree likes this.
  27. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,

    Unfortunately, this is not a behaviour we can change in the DampedTransform constraint. While you can have different scale factors in the hierarchy, these need to be set before the constraint is activated, and cannot be changed afterwards.

    This constraint has been built to damp and maintain an offset between two game objects. These can be directly parented to each other, like the example we've provided in the samples, or at different locations in the hierarchy. The latter case is why we can't really support dynamic scaling since we need to write back the damped values in world coordinates to make sure the offset remains the same.

    If your use case specifically involves a chain of transform you wish to damp like the one in the samples, then, you could write your own custom constraint that reads and writes in local coordinates.
     
    KalOBrien and Threeyes like this.
  28. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80

    Thanks for the detail, I see, to maintian the flexibility we have to sacrifice something!

    For anyone who faces this problem, here's my solution:
    Code (CSharp):
    1.  
    2.  
    3. public class RigBuilderHelper : MonoBehaviour
    4. {
    5.     RigBuilder Comp;
    6.     public List<Transform> listBone = new List<Transform>();//Each Bone's Transform
    7.     public List<Vector3> listDefaultBonePosition = new List<Vector3>();//Each Bone's default local position
    8.     public List<Vector3> listDefaultBoneRotation = new List<Vector3>();//Each Bone's default local rotation
    9.  
    10.     //Call it before game begin
    11.     [ContextMenu("SaveJoint")]
    12.     public void SaveJoint()
    13.     {
    14. #if UNITY_EDITOR
    15.         //Keep in mind that BoneRenderer is editor-only script
    16.         listBone.Clear();
    17.         listDefaultBonePosition.Clear();
    18.         listDefaultBoneRotation.Clear();
    19.         for (int i = 0; i != GetComponent<BoneRenderer>().transforms.Length; i++)
    20.         {
    21.             Transform tfChild = GetComponent<BoneRenderer>().transforms[i];
    22.             listBone.Add(tfChild);
    23.             listDefaultBonePosition.Add(tfChild.localPosition);
    24.             listDefaultBoneRotation.Add(tfChild.localEulerAngles);
    25.         }
    26. #endif
    27.     }
    28.  
    29.   //Call it after you scale the Joint
    30.   void RebuildJoint()
    31.     {    
    32.         Comp.Clear();//Stop cur Job
    33.  
    34.         for (int i = 0; i != listBone.Count; i++)
    35.         {
    36.             Transform tfChild = listBone[i];
    37.             tfChild.localPosition = listDefaultBonePosition[i];
    38.             tfChild.localEulerAngles = listDefaultBoneRotation[i];
    39.         }
    40.         Comp.Build();//Recreate job using current state
    41. }
     
  29. brummer

    brummer

    Joined:
    Jul 3, 2013
    Posts:
    31
    @simonbz @Jebtor
    Kind of an old thread, but it seems to still have the same issues.
    Specifically, i have a few questions;
    -Why do i need an animator for this entire rig to work? I could see plenty of use cases when one would not want/need the overhead of an animator just to implement a simple IK.
    -Even if i have no animations, animation controller, avatar, the rig seems to work...
    BUT: as soon as i apply any non-uniform scaling, it breaks.
    Even though just scaling the root in editor doesn't immediately break the model when the game isn't running, but as long as the rigging system is involved, it breaks.
    Why can't we just have some sort of option for stretchy IK, like maya and such have, that wouldn't break from this?
     
    behzatbabil and TorbenDK like this.