Search Unity

Getting bone position during animation

Discussion in 'Animation' started by Prefab, Apr 7, 2020.

  1. Prefab

    Prefab

    Joined:
    May 14, 2013
    Posts:
    68
    I am trying to loop through a character skeleton at runtime and determine which bone is the furtherest from the root bone along the y axis. I have found though that the y position of the bones does not change while the character is animating so the calculation I do below always gets me the same head bone even if the character puts his hands above his head.

    How do I go about getting the actual bone positions during animations?

    Code (CSharp):
    1. public void FindHighestBone(Transform[] allBonesToCheck)
    2.     {
    3.         float HighestDistance = 0;
    4.         Transform highestBoneTemp = null;
    5.  
    6.         foreach (Transform boneTransform in allBonesToCheck)
    7.         {
    8.             float checkedDistance = boneTransform.position.y - characterRoot.position.y;
    9.  
    10.             //Debug.Log(checkedDistance);
    11.  
    12.             if (checkedDistance > HighestDistance)
    13.             {
    14.                 highestBoneTemp = boneTransform;
    15.                 HighestDistance = checkedDistance;
    16.                 //Debug.Log(highestBoneTemp);
    17.                 //Debug.Log(HighestDistance);
    18.             }
    19.         }
    20.  
    21.         highestBone = highestBoneTemp;
    22.     }
     
  2. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    I tried similar setup and I do get different bones when my app is running. Are you sure you update your transforms every frame?

    i.e. do something like:
    Code (CSharp):
    1. void Update()
    2. {
    3.    Transform[] allBones = gameObject.GetComponentsInChildren<Transform>();
    4.    FindHighestBone(allBones);
    5. }
     
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Do you have Optimize Transforms enabled in your model's Import Settings? Because if so then the hands won't actually have a Transform so it won't have anything to check.
     
  4. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    You mean Optimize Game Objects in Rig tab? If you're talking about that, no, I don't have it on in this specific case when I tested this.
     
  5. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Yeah, that's the one.

    Are you sure the hand transform is actually included in your array?

    Can you select it in the Hierarchy and see if it moves around in the scene view while the animation plays?
     
  6. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Yes the transform is definitely moving, if I got Hand.L selected (my left hand transform) it moves as if one would expect it to, i.e. it stays where it is when animation is going on. (just checked this again to be sure.)

    Btw, just out of curiosity, I'm not expert in every detail of Animator, but try also changing culling mode in Animator. I got Always Animate on when I'm doing tests, I've imagined it would force the mesh to animate all the time, be it off screen or not.
     
  7. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    If the bone is moving in the scene but your code isn't getting the right value then you must have a reference to the wrong object.

    Try using Debug.Log(boneTransform.name, boneTransform) so that when you click on the log message it highlights the specified object in the Hierarchy so you can make sure it is checking the right ones.
     
  8. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Is that a quote from somewhere? Or what. You lost me a bit. I'm able to get bone positions fine and I've used that to make objects tag along (like an item follows the hand etc.) so I think the transforms are fine.
     
  9. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    You need to narrow down the actual problem. If the objects in the scene look right, then use some debug logging to see what values your script is getting.
     
  10. Prefab

    Prefab

    Joined:
    May 14, 2013
    Posts:
    68
    Hi @Kybernetik & @Olmi , here is the full script and yes it is running in update. When I select a head, spine, arm etc bone and watch the position in the inspector while the character is animating, the values do not change at all, even though the bone is clearly changing position based on the animation. Most of the bones do have kinematic rigidbodies for ragdoll purposes, but this shouldn't matter should it? The FindFurthestBone below does return accurate result, it is just the FindHighestBone which is always returning the same bone, the top of the head.

    I'm really not sure what I need to do here, I would've though this would be fairly straight forward to do.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraAnchor : MonoBehaviour
    6. {
    7.     public Transform[] allBonesToCheck;
    8.     public Transform characterRoot;
    9.     public Transform furthestBone;
    10.     public Transform highestBone;
    11.     private Transform thisTransform;
    12.  
    13.     // Start is called before the first frame update
    14.     void Start()
    15.     {
    16.         thisTransform = transform;
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.  
    23.         FindFurthestBone(allBonesToCheck);
    24.         FindHighestBone(allBonesToCheck);
    25.         if (furthestBone != null && highestBone != null)
    26.         {
    27.             thisTransform.position = new Vector3(thisTransform.position.x, highestBone.position.y, furthestBone.position.z);
    28.         }
    29.     }
    30.  
    31.     public void FindFurthestBone(Transform[] allBonesToCheck)
    32.     {
    33.         float FurthestDistance = 0;
    34.         Transform furthestBoneTemp = null;
    35.  
    36.         foreach (Transform boneTransform in allBonesToCheck)
    37.         {
    38.             float checkedDistance = Mathf.Abs(boneTransform.position.z - characterRoot.position.z);
    39.             //Debug.Log(checkedDistance);
    40.  
    41.             if (checkedDistance > FurthestDistance)
    42.             {
    43.                 furthestBoneTemp = boneTransform;
    44.                 FurthestDistance = checkedDistance;
    45.                 //Debug.Log(furthestBoneTemp);
    46.                 //Debug.Log(FurthestDistance);
    47.             }
    48.         }
    49.  
    50.         furthestBone = furthestBoneTemp;
    51.     }
    52.  
    53.     public void FindHighestBone(Transform[] allBonesToCheck)
    54.     {
    55.         float HighestDistance = 0;
    56.         Transform highestBoneTemp = null;
    57.  
    58.         foreach (Transform boneTransform in allBonesToCheck)
    59.         {
    60.             float checkedDistance = boneTransform.position.y - characterRoot.position.y;
    61.  
    62.             //Debug.Log(checkedDistance);
    63.  
    64.             if (checkedDistance > HighestDistance)
    65.             {
    66.                 highestBoneTemp = boneTransform;
    67.                 HighestDistance = checkedDistance;
    68.                 Debug.Log(highestBoneTemp);
    69.                 //Debug.Log(HighestDistance);
    70.             }
    71.         }
    72.  
    73.         highestBone = highestBoneTemp;
    74.     }
    75. }
    76.  
     
  11. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    @Prefab did you try different Import settings and different Animator culling mode settings yet. I'll test your script just to see what's going on...
     
  12. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    @Prefab I'm not sure if all the logic in that script is correct (highest bone gives weird results) but it does update here, in my character I happened to use.

    But please clarify which values are you *exactly* talking about? Those two exposed fields (furthest bone, highest bone) do update here... So those don't update for you?
     
  13. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Just in case you want to compare the import etc. settings, here's mine from my test model:

    Model:
    character_model.png

    Rig:
    character_rig.png

    Animation:

    character_animation.png


    Animator:
    character_Animator.png
     
  14. Prefab

    Prefab

    Joined:
    May 14, 2013
    Posts:
    68
    FurthestBone appears to be updating correctly, but highestBone always stays as the head bone even during an animation where other bones become positioned higher on the y axis. I am trying to find the highest positioned bone during animations which should change while the bones are animating. So I am comparing the position y of every bone to the root bone, which should hopefully always be at the lowest point.
     
  15. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    The Inspector shows the local position of the selected object which does not generally change during animations. Bones are usually only rotated so their children move in world space while their local positions stay the same. You might be interested in Inspector Gadgets (link in my signature) which lets you toggle the Inspector between local and world space.

    Try using Debug.DrawLine to visualise the positions of each of the bones in the scene view which might help you track down the issue.
     
  16. Prefab

    Prefab

    Joined:
    May 14, 2013
    Posts:
    68
    Sure I'll try that
     
  17. TKDHayk

    TKDHayk

    Joined:
    Dec 22, 2015
    Posts:
    131
    The issue is that the animator resets the position of the skeleton to the default position, and then changes it to the next position. You need to execute your script in late update I think. Let me know if it works ?
     
  18. jbgore-shadowhealth

    jbgore-shadowhealth

    Joined:
    Apr 9, 2018
    Posts:
    1
    Thank you TKDHayk, this is the answer I have been looking for