Search Unity

Access and limit muscles setting in human avatar

Discussion in 'Animation' started by jhuh3226, Mar 2, 2019.

  1. jhuh3226

    jhuh3226

    Joined:
    Oct 24, 2018
    Posts:
    9
    Hello, I'm trying to modify the limit (min, max) of the muscles setting of a human avatar.
    I'm currently working with Kinect SDK to move my avatar according to the movement of the human in front of it and trying to find a way to modify muscles setting easily via code.

    I have found some discussions on this issue(https://stackoverflow.com/questions/48740511/unity-3d-move-humanoid-head-muscles-using-script?rq=1) and reference in the Unity documentation using HumanLimit (https://docs.unity3d.com/ScriptReference/HumanLimit-max.html) though haven't found the clear way or example to do it.

    Is there anyone who can help me with how to set limitation using HumanLimit.min and HumanLimit.max? Below is the code I have found from the Github(https://github.com/NumesSanguis/Bas...ree/master/unity_head_rotation/Assets/Scripts)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MuscleLimit : MonoBehaviour
    6. {
    7.     //added
    8.     public Vector3 min;
    9.  
    10.     //   Human muscle stuff
    11.     HumanPoseHandler humanPoseHandler;
    12.     HumanPose humanPose;
    13.     HumanLimit humanLimit;
    14.     Animator anim;
    15.  
    16.     // Indexes to muscles
    17.     // 9: Neck Nod Down-Up min: -40 max: 40
    18.     // 10: Neck Tilt Left-Right min: -40 max: 40
    19.     // 11: Neck Turn Left-Right min: -40 max: 40
    20.     // 12: Head Nod Down-Up min: -40 max: 40
    21.     // 13: Head Tilt Left-Right min: -40 max: 40
    22.     // 14: Head Turn Left-Right min: -40 max: 40
    23.  
    24.  
    25.     //   Bone stuff
    26.     Transform head;
    27.  
    28.     // Muscle name and index lookup (See in Debug Log)
    29.     void LookUpMuscleIndex()
    30.     {
    31.         string[] muscleName = HumanTrait.MuscleName;
    32.         int i = 0;
    33.         while (i < HumanTrait.MuscleCount)
    34.         {
    35.             Debug.Log(i + ": " + muscleName[i] +
    36.                 " min: " + HumanTrait.GetMuscleDefaultMin(i) + " max: " + HumanTrait.GetMuscleDefaultMax(i));
    37.             i++;
    38.         }
    39.      
    40.     }
    41.  
    42.     // Set character in fetus position
    43.     void ResetMuscles()
    44.     {
    45.         // reset all muscles to 0
    46.         for (int i = 0; i < humanPose.muscles.Length; i++)
    47.         {
    48.             //Debug.Log (humanPose.muscles [i]);
    49.             humanPose.muscles[i] = 0;
    50.         }
    51.     }
    52.  
    53.  
    54.     ////   !!! Human Pose approach !!!
    55.     void Start()
    56.     {
    57.         // https://forum.unity.com/threads/humanposehandler.430354/
    58.  
    59.         // get attached Animator controller
    60.         anim = GetComponent<Animator>();
    61.  
    62.         // run this if you want the indexes to muscles on your character
    63.         LookUpMuscleIndex();
    64.  
    65.         // TODO keeping body above plane
    66.         //Vector3 current_position = transform.position;
    67.  
    68.         // get human pose handler
    69.         humanPoseHandler = new HumanPoseHandler(anim.avatar, transform);
    70.         // get human pose
    71.         humanPose = new HumanPose();
    72.  
    73.         // TODO keeping body above plane
    74.         //humanPose.bodyPosition = current_position;
    75.  
    76.         // reference pose to pose handler
    77.         humanPoseHandler.GetHumanPose(ref humanPose);
    78.  
    79.         // set a specific musle; 9: Neck Nod Down-Up
    80.         humanPose.muscles[39] = 0f;
    81.         Debug.Log(humanPose.muscles[9]);
    82.  
    83.         // use pose information to actually set the pose; doesn't work so far
    84.         //humanPoseHandler.SetHumanPose(ref humanPose);
    85.  
    86.     }
    87.  
    88.     // Update is called once per frame
    89.     void Update()
    90.     {
    91.         //humanPose.muscles[39] = 0f;
    92.         //humanPoseHandler.SetHumanPose(ref humanPose);
    93.     }
    94. }
     
  2. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    229
    Hi,

    In version 2019 it's now possible to do the following but the limits seem to have a bug where they are always 0.

    Code (CSharp):
    1. HumanBone[] humanBones = animator.avatar.humanDescription.human;
    2.             Debug.Log("Avatar Name:" + animator.avatar.name);
    3.             for (int i = 0; i < humanBones.Length; i++) {
    4.                 humanBones[i].limit.useDefaultValues = false;              
    5.                 Debug.Log("BoneName:" + humanBones[i].boneName + "-->" + humanBones[i].humanName + " || (Center):" + humanBones[i].limit.center + " (Min):" + humanBones[i].limit.min + " (Max):" + humanBones[i].limit.max + " (AxisLenght):" + humanBones[i].limit.axisLength);
    6.             }
     
  3. yourzombiemop

    yourzombiemop

    Joined:
    Mar 22, 2020
    Posts:
    1
    Hey, this reference helped a lot!! I recon I've spent over 24 working hours (I do this as a hobby) looking for a solution to this issue. I kept finding the function connected to HumanTrait, which only returned the defaults.. I have been crawling through the documentation on everything related to muscles. I had found the HumanPose.muscles related content, but sadly stumbled across and missed the fact that you can get an Avatar's Human Description information when I looked through the Avatar documentation.. I just want to say, thank you SO much for this final tidbit of information that provided the solution I needed. And, by the way, the bug that set all values to zero was patched.

    Without further ado, here is my code to gather the information attached in my screenshot:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4.  
    5. public class IKControl : MonoBehaviour
    6. {
    7.     protected Animator animator = null;
    8.     protected Avatar avatar = null;
    9.     protected HumanDescription humanDescription;
    10.     protected HumanBone[] avatarBones;
    11.     protected HumanPose humanPose;
    12.     protected HumanPoseHandler humanPoseHandler = null;
    13.  
    14.     public bool ikActive = true;
    15.  
    16.     void Start()
    17.     {
    18.         animator = GetComponent<Animator>();
    19.         avatar = animator.avatar;
    20.         humanDescription = animator.avatar.humanDescription;
    21.         avatarBones = humanDescription.human;
    22.  
    23.         //LogDefaultMuscleIndex();
    24.         LogAvatarMuscleIndex();
    25.  
    26.         humanPoseHandler = new HumanPoseHandler(avatar, transform);
    27.         humanPoseHandler.GetHumanPose(ref humanPose);
    28.     }
    29.  
    30.     void Update()
    31.     {
    32.  
    33.     }
    34.  
    35.     void OnAnimatorIK()
    36.     {
    37.  
    38.     }
    39.  
    40.     void LateUpdate()
    41.     {
    42.  
    43.     }
    44.  
    45.     private void LogDefaultMuscleIndex()
    46.     {
    47.         for (int i = 0; i < HumanTrait.MuscleCount; i++)
    48.         {
    49.             Debug.Log(i + ": " + HumanTrait.MuscleName[i]);
    50.         }
    51.     }
    52.  
    53.     private void LogAvatarMuscleIndex()
    54.     {
    55.         Debug.Log("There are " + avatarBones.Length + " bones in this avatar; their data is as follows.");
    56.         for (int i = 0; i < avatarBones.Length; i++)
    57.         {
    58.             Debug.Log(
    59.                 "Muscle ID: " + i +
    60.                 "\nOriginal Bone Name: " + avatarBones[i].boneName +
    61.                 "\nMecanim Bone Name: " + avatarBones[i].humanName +
    62.                 "\nCenter Rotation (Euler): " + avatarBones[i].limit.center +
    63.                 "\nMaximum Rotation (Euler): " + avatarBones[i].limit.max +
    64.                 "\nMinimum Rotation (Euler): " + avatarBones[i].limit.min
    65.                 );
    66.         }
    67.     }
    68. }
    69.  
    ConsoleOutput.png
     
  4. SOICGeek

    SOICGeek

    Joined:
    Jun 25, 2019
    Posts:
    78
    I did full-body tracking with VR for part of my master's thesis a few years back. When I did it, I sort of bypassed Mecanim a bit. I set the hips, back, and head from the Kinect data, but used the position of the arms using IK (also from the Kinect data). Same with the legs. There's a trick to it, though - you have to grab the position of the hips BEFORE you modify it, then again AFTER you modify it, and then get the difference between those points. Apply that difference to the IK positions. If you don't, then your IK will end up in the wrong position. As for elbows and knees, just set those positions as the IK pole vectors (Unity calls them "hints"). Doing it that way eliminates any rotation offset issues, and it will be precise to the actor's pose.

    Hope that helps!
     
  5. sickybee

    sickybee

    Joined:
    Jun 5, 2017
    Posts:
    4
    when the human limit will evaluate bone rotation? OnAnimatorIK seems will not respect HumanLimit.
     
  6. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    229