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

Changing two bone IK target at runtime gives many warnings

Discussion in 'Animation Rigging' started by xjjon, Sep 18, 2020.

  1. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    610
    Could not resolve 'Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/Bip001 Spine2/2hShootMount/Uzi-2h(Clone)/LeftHandGrip' because it is not a child Transform in the Animator hierarchy.

    Basically I am mounting 2 handed weapons at runtime for the model and then assigning the constraint targets.

    1) Instantiate gun prefab
    2) Disable animator
    3) Reset transform values, etc
    3) Set IK targets and set weights to 1
    4) Re-build rig

    Code (CSharp):
    1.  
    2.  
    3. public TwoBoneIKConstraint LeftHandIK;
    4. public TwoBoneIKConstraint RightHandIK;
    5.  
    6. public Animator Animator;
    7. public RigBuilder RigBuilder;
    8.  
    9.  
    10. public void Load(GameObject WeaponPrefab) {
    11.   _weapon = Instantiate(WeaponPrefab, RifleMount);
    12.   Animator.enabled = false;
    13.   _weapon.transform.localPosition = Vector3.zero;
    14.   _weapon.transform.localRotation = Quaternion.Euler(Vector3.zero);
    15.   _weapon.transform.localScale = Vector3.one;
    16.   LeftHandIK.data.target = _weapon.LeftHandIK;
    17.   RightHandIK.data.target = _weapon.RightHandIK;
    18.   LeftHandIK.weight = 1;
    19.   RightHandIK.weight = 1;
    20.   RigBuilder.Build();
    21.   Animator.enabled = true;
    22. }
    23.  
    And to un-mount the weapon:

    Code (CSharp):
    1.            
    2. Animator.enabled = false;
    3. LeftHandIK.weight = 0;
    4. RightHandIK.weight = 0;
    5. LeftHandIK.data.target = null;
    6. RightHandIK.data.target = null;
    7. if (_weapon != null)
    8. {
    9.       Destroy(_weapon.gameObject);
    10. }
    11. Animator.enabled = true;
    Any reason this might result in all these warnings being printed? It's around 10~ lines per second for each IK target.

    Could not resolve 'Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/Bip001 Spine2/2hShootMount/Uzi-2h(Clone)/LeftHandGrip' because it is not a child Transform in the Animator hierarchy.
     
  2. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,

    Difficult to say, we're missing details as to how your project is set up.

    How is that prefab hierarchy you're instantiating set up? Is this sub-hierarchy also animated?
    Do you have the same errors if the weapon prefab starts up in the hierarchy, or is it triggered by moving game objects around?

    Also, is that warning thrown off when you mount the weapon, or when it's unmounted? Removing a game object from the animated hierarchy does not remove its associated bindings, so this might indeed throw off errors.
     
    Last edited: Sep 23, 2020
  3. Bimaokai

    Bimaokai

    Joined:
    Jul 21, 2017
    Posts:
    19
    Hi. I know this is very old, but i have the same problem
    Where I have no problem at all is pulling the weapon out. I do this:

    I get the Weapon out of the WPN_HOLDER_2HRIGHT
    Code (CSharp):
    1. Transform weapon2Draw = fromSlot.weaponHolder.GetChild(0);
    2. weapon2Draw.parent = player.rightHandPos;
    3. weapon2Draw.localPosition = Vector3.zero;
    4. weapon2Draw.localRotation = Quaternion.identity;
    After the animation i put the weapon in the WeaponDrawHolder:
    Code (CSharp):
    1. TwoBoneIKConstraint rightHandIK = player.rightHandIKTarget.parent.GetComponent<TwoBoneIKConstraint>();
    2. rightHandIK.data.target = fromSlot.weapon.rightHandWeaponHandle;
    3. TwoBoneIKConstraint leftHandIK = player.leftHandIKHint.parent.GetComponent<TwoBoneIKConstraint>();
    4. leftHandIK.data.target = fromSlot.weapon.leftHandWeaponHandle;
    5. fromSlot.weapon.transform.parent = player.weaponDrawHolder;
    6. rigBuilder.enabled = true;
    whereas the RigBuilder is on the Player Object.

    Then comes the problematic part:
    I try to put the thing back to the right Hand (RH_POS) and removing the IK Targets away from the weapon holders.

    Code (CSharp):
    1. rigBuilder.enabled = false;
    2.  
    3. TwoBoneIKConstraint rightHandIK = player.rightHandIKTarget.parent.GetComponent<TwoBoneIKConstraint>();
    4. rightHandIK.data.target = player.rightHandIKTarget;
    5. TwoBoneIKConstraint leftHandIK = player.leftHandIKHint.parent.GetComponent<TwoBoneIKConstraint>();
    6. leftHandIK.data.target = player.leftHandIKTarget;
    7.  
    8. fromSlot.weapon.transform.parent = player.rightHandPos;
    9. fromSlot.weapon.transform.localPosition = Vector3.zero;
    10. fromSlot.weapon.transform.localRotation = Quaternion.identity;
    If i do this, i get the following messages and i don't know why this is coming, cause i have the rifle still in the Animator Hierarchy (Player).
    Code (CSharp):
    1. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/RHHandle' because it is not a child Transform in the Animator hierarchy.
    2. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/RHHandle' because it is not a child Transform in the Animator hierarchy.
    3. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/RHHandle' because it is not a child Transform in the Animator hierarchy.
    4. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/LHHandle' because it is not a child Transform in the Animator hierarchy.
    5. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/LHHandle' because it is not a child Transform in the Animator hierarchy.
    6. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/LHHandle' because it is not a child Transform in the Animator hierarchy.
    7. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/RHHandle' because it is not a child Transform in the Animator hierarchy.
    8. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/RHHandle' because it is not a child Transform in the Animator hierarchy.
    9. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/RHHandle' because it is not a child Transform in the Animator hierarchy.
    10. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/LHHandle' because it is not a child Transform in the Animator hierarchy.
    11. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/LHHandle' because it is not a child Transform in the Animator hierarchy.
    12. Could not resolve 'WeaponDrawHolder/TwoHandScifiRifle_Red/LHHandle' because it is not a child Transform in the Animator hierarchy.
    13.  
     

    Attached Files:

  4. Bimaokai

    Bimaokai

    Joined:
    Jul 21, 2017
    Posts:
    19
    Found a solution to that. I changet it to disabling the RigLayers seperately und calling each time "rigBuilder.enabled = true" to update the behaviors.

    This removed the warnings. Is that a bug or is this how it should behave ?
     
  5. jomath229

    jomath229

    Joined:
    Nov 7, 2013
    Posts:
    3
    What do you mean by disabling the rigLayers separately? Do you mean you removed the IK rig layer? I'm facing the same problem and I find these errors annoying since they mess up the behaviours of other layers when they're called.
     
  6. beevik_

    beevik_

    Joined:
    Sep 27, 2020
    Posts:
    92
    I'm seeing similar warnings after setting a TwoBoneIKConstraint's target to null at runtime. The "could not resolve" warning appears for the target reference that was just set to null.

    Is it possible that there's some sort of timing issue at play, where the constraint's target is being updated in the main thread but the reference to the constraint's target is happening in an animation job (or thread)?

    What is the proper way to update a constraint's target at runtime? I could not find any documentation describing how this should be done. I've been updating the target in the Update() call and then calling the rig builder's Build() method, but I'm not sure if that is the correct way to be doing things. Clearly I'm doing something wrong because I'm getting these warnings.
     
  7. beevik_

    beevik_

    Joined:
    Sep 27, 2020
    Posts:
    92
    @simonbz You asked about how the original poster's project was set up. I submitted a Unity bug report containing a project that reproduces these warnings. Case # is 1382020.
     
  8. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,

    This is by design in Animation Rigging.

    When RigBuilder is initialized at runtime, it's converting the transform components you're referencing in constraints to animation bindings.

    You can think of it just like channels in an animation clip. If you were to move your game objects while they were being animated by your curves, they would simply stop animating. In animation rigging, your constraints are evaluated in the same way. They are reading from the animation stream that has been previously written to by your animation clips and are writing back to the animation stream.

    I see two ways you can handle this with Animation Rigging.

    1- Build your rig accordingly. If you need to change the target transform of your TwoBoneIK to known transforms in your rig or in the scene at runtime, then you can create a MultiParentConstraint in your rig with multiple source transforms. The constrained transform of MultiParent can then be used as your target transform for TwoBoneIK instead. You only need to dynamically change the weights on the MultiParentConstraint afterwards to dynamically change your target transform.

    2- Rebind the Animator. By rebinding the animator and rebuilding the rig in RigBuilder, you'll recalculate the animation bindings for the current GameObject hierarchy. This is a costly operation however, and you wouldn't want to do that too often in your animation.

    Code (CSharp):
    1. var animator = GetComponent<Animator>();
    2. var rigBuilder = GetComponent<RigBuilder>();
    3.  
    4. rigBuilder.Build();
    5. animator.Rebind();
     
    Maskeowl, Howtofail and beevik_ like this.
  9. beevik_

    beevik_

    Joined:
    Sep 27, 2020
    Posts:
    92
    I attempted this second way of solving the problem (since it's more relevant to my scenario) but I still ran into the same issue. As soon as Rebind is called, the 'Could not resolve' warnings are emitted. (This happens despite the fact that I've set the offending TwoBodyIK's target reference to null.) If I click the warning in the Unity Editor, it shows the warning being emitted within the call to Rebind.

    Any idea why Rebind would trigger the warning? This only happens when I remove a transform from the hierarchy; it never happens when I add transforms to the hierarchy.
     
    Last edited: Nov 30, 2021
  10. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    This happens because the missing transform is still bound to the animator. Calling `RigBuilder.Build` will register all new transform handles in the Animator, but it will not unbind unused handles.

    You'll need to call the following functions (version 2021.1 and above) to unbind transform handles:
    https://docs.unity3d.com/2021.1/Doc...atorJobExtensions.UnbindAllStreamHandles.html
    https://docs.unity3d.com/2021.1/Doc...matorJobExtensions.UnbindAllSceneHandles.html

    Code (CSharp):
    1. var animator = GetComponent<Animator>();
    2. var rigBuilder = GetComponent<RigBuilder>();
    3.  
    4. animator.UnbindAllStreamHandles();
    5. animator.UnbindAllSceneHandles();
    6.  
    7. rigBuilder.Build();
    8. animator.Rebind();
     
    Maskeowl and beevik_ like this.
  11. beevik_

    beevik_

    Joined:
    Sep 27, 2020
    Posts:
    92
    Thanks. This caused the warnings to go away.

    Is it possible to unbind a specific stream handle (or scene handle) from an animator so that I don't have to unbind all of them? As far as I can tell, AnimatorJobExtensions has extension methods for binding individual transforms, but none for unbinding.

    In the somewhat contrived example we've been discussing, unbinding all handles makes sense because the animator is just going to perform a full Rebind. But I have another scenario where I'd like to unbind a specific stream handle, because I don't want to call Rebind. (I'm using animation playables in this scenario instead of the animation rigging package.)

    This is probably more of a general Animation/Playables question than a rigging-specific question.
     
    Last edited: Dec 2, 2021
  12. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    It's not possible to only unbind a single scene or stream handle with the current API.

    When we introduced `UnbindAllStreamHandles` and `UnbindAllSceneHandles` in the API, we were also looking to add functions to unbind single properties to mirror `BindSceneTransform` and `BindStreamTransform`. However, we ultimately decided against it.

    Since we don't control what systems can use Animation C# Jobs and what handles they can bind, a system like Animation Rigging can't take the decision to unbind a handle that may be used by another system. We felt like providing an Unbind api for single properties would cause issues if users were writing constraints where they would Bind/Unbind properties in their `AnimationJobBinder`.

    Therefore, `UnbindAllStreamHandles` and `UnbindAllSceneHandles` are provided as advanced functions to clean up the animation c# jobs handles in the `Animator` for cases like yours.
     
  13. beevik_

    beevik_

    Joined:
    Sep 27, 2020
    Posts:
    92
    Thank you for your thorough and helpful responses. They've been really helpful and I appreciate the time you put into them.

    Although I understand your team's reasons for deciding against implementing the unbinding of specific transforms, I'm struggling to figure out how best to deal with it. Maybe I can provide further context to see if there is a better solution available.

    In my system, I have a playables graph containing multiple custom `AnimationScriptPlayable` nodes in it. Each of these playables has a job with its own stream transform bindings. Sometimes one of the animation scripts requires an updated transform binding, so I rebuild that job's data with new transform bindings. However, because I cannot simply remove the old unnecessary bindings, I have to remove all of them with `UnbindAllStreamHandles`. This means I also need to update the job data for all the other (unrelated) script playables, even though none of their bindings changed. This is currently what I'm doing, and it works. But it feels like a lot of wasted processing and a bit of a kludge.

    I should mention that my system is no longer using Animation Rigging at all. I wrote it from scratch using playables after struggling to get Rigging to work with constraint retargeting. (Rebuilding the entire rig was causing animation hitches, and rebinding the animator is, as you noted, computationally expensive.) It's unfortunate that there is no easy way to update a transform binding associated with a playable graph without unbinding all of the bindings.

    I'm not sure what the right answer is, but it would be nice if there were a performant and straightfoward way to rebind transforms at runtime.

    Also, I discovered that the order of calls to `UnbindAllStreamHandles` and `UnbindAllSceneHandles` matters. If you unbind all scene handles before unbinding all stream handles, you will still get 'Cannot resolve' warnings. This seems like a bug?
     
  14. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    I don't see any obvious reason why the order should cause an issue. If you can report a bug for this using the Unity bug reporter, that would be much appreciated :)
     
  15. Bimaokai

    Bimaokai

    Joined:
    Jul 21, 2017
    Posts:
    19
    Just to share this solved my problem for my weapn drawing problems:
    • disable all rig layers in rigbuilder
    • set the target if the IK to the hand and not the weapon which is moved
    • move the weapon
    Code (CSharp):
    1. private void DisableEnableRigBuilder(bool enabled)
    2.         {
    3.             foreach (RigLayer layer in rigBuilder.layers)
    4.             {
    5.                 layer.active = enabled;
    6.             }
    7.         }
    8.  
    9.         private IEnumerator EnableDisableRigBuilderAfterAnimation(WeaponSlot fromSlot, bool attach)
    10.         {
    11.             if (!attach)
    12.             {
    13.  
    14.                 DisableEnableRigBuilder(false);
    15.                 rigBuilder.enabled = true;
    16.  
    17.                 TwoBoneIKConstraint rightHandIK = player.rightHandIKTarget.parent.GetComponent<TwoBoneIKConstraint>();
    18.                 rightHandIK.data.target = player.rightHandIKTarget;
    19.                 TwoBoneIKConstraint leftHandIK = player.leftHandIKTarget.parent.GetComponent<TwoBoneIKConstraint>();
    20.                 leftHandIK.data.target = player.leftHandIKTarget;
    21.  
    22.                 fromSlot.weapon.transform.parent = player.rightHandPos;
    23.                 fromSlot.weapon.transform.localPosition = Vector3.zero;
    24.                 fromSlot.weapon.transform.localRotation = Quaternion.identity;
    25.                 player.weaponDrawHolder.localPosition = Vector3.zero;
    26.                 player.weaponDrawHolder.localRotation = Quaternion.identity;
    27.  
    28.             }
    29.  
    30.             bool endOfAnimationReached = false;
    31.             while (!endOfAnimationReached)
    32.             {
    33.                 AnimatorStateInfo currentState = animator.GetCurrentAnimatorStateInfo(1);
    34.                 if (currentState.IsName(NoNoNZoneConstants.Player.DRAW_2HR_WEAPON_ANIM_NAME) && currentState.normalizedTime >= 1.0f)
    35.                 {
    36.                     if (attach)
    37.                     {
    38.                         TwoBoneIKConstraint rightHandIK = player.rightHandIKTarget.parent.GetComponent<TwoBoneIKConstraint>();
    39.                         rightHandIK.data.target = fromSlot.weapon.rightHandWeaponHandle;
    40.                         TwoBoneIKConstraint leftHandIK = player.leftHandIKTarget.parent.GetComponent<TwoBoneIKConstraint>();
    41.                         leftHandIK.data.target = fromSlot.weapon.leftHandWeaponHandle;
    42.  
    43.                         // set the weapon into the constraint position
    44.                         fromSlot.weapon.transform.parent = player.weaponDrawHolder;
    45.                         fromSlot.weapon.transform.localPosition = Vector3.zero;
    46.                         fromSlot.weapon.transform.localRotation = Quaternion.identity;
    47.  
    48.                         // set the pivot point of the weapon
    49.                         Vector3 pivotDistance = fromSlot.weapon.pivotPoint.localPosition - fromSlot.weapon.transform.localPosition;
    50.                         fromSlot.weapon.transform.localPosition -= pivotDistance;
    51.  
    52.                         rigBuilder.enabled = true;
    53.                         DisableEnableRigBuilder(true);
    54.                     }
    55.  
    56.                     endOfAnimationReached = true;
    57.                 }
    58.                 yield return null;
    59.             }
    60.         }
     
  16. unity_ZYsHk4nnsD81HQ

    unity_ZYsHk4nnsD81HQ

    Joined:
    Jul 11, 2021
    Posts:
    1
    I have similar problem on my first person shooter game, i'm trying to change target of
    TwoBoneIKConstraint when player picks up gun, target becomes picked weapon and in inspector it changes and its fine but in game it wont take effect hands still follow old target. help please im dumb.

    GameObject.Find("ShotGunRightHandIK").GetComponent<TwoBoneIKConstraint>().data.target = Weapon.transform;
     
  17. Bimaokai

    Bimaokai

    Joined:
    Jul 21, 2017
    Posts:
    19
    I had the problem, when the constraint was not correctly set on the bones. That code of your works well for me.

    For me this is the contstraint.
    upload_2022-1-9_16-25-38.png
    When i attach the weapon i just set the target to the right handle of the weapon, which has to be inside your bone structure. I created a special weapon holder object for that.
    upload_2022-1-9_16-26-57.png