Search Unity

How to change muscles values from code? (animate character with code)

Discussion in 'Animation' started by ReignRavel, Apr 20, 2017.

  1. ReignRavel

    ReignRavel

    Joined:
    Apr 20, 2017
    Posts:
    26
    Hi,
    1.I would like to animate my character with random footsteps, so I would like to move the bones myself. There is the muscle setup page, and some code like this :
    Code (CSharp):
    1. string[] muscleName = HumanTrait.MuscleName;
    2.         int i = 0;
    3.         while (i < HumanTrait.MuscleCount) {
    4.             Debug.Log(muscleName[i] + " min: " + HumanTrait.GetMuscleDefaultMin(i) + " max: " + HumanTrait.GetMuscleDefaultMax(i));
    5.             i++;
    6.         }
    How can I link "HumanTrait" with my character? Something like myCharacter.GetComponent<Animator>().GetComponent<HumanTrait>()...

    2.Also, my character animation plays well in Legacy mode, but not in Humanoid mode, the muscles are correctly set up though, anyone would know how to fix this?
    Thanks
     
  2. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    Hi,

    You cannot change the muscle value at runtime, the only way to generate muscle curve is to use the importer and import your clips as humanoid. That been said we are working on exposing this in a future release but it not available yet.

    Most issue with humanoid character are caused by either a bad T-pose, or if the rig is not correctly setup.
    Do you see any import warning when you import the animation file or your rig in the inspector?
     
  3. ReignRavel

    ReignRavel

    Joined:
    Apr 20, 2017
    Posts:
    26
    Thanks, so I have got this import message :

    1.png

    I also don't have 2 of the bones, maybe it is part of the problem (chest and the one above chest).

    ____

    My goal is to get something like this, the legs are following the position of the body dynamically :


    I was looking for a way to move a target bone as it is in Blender (the inverse kinematic constraint) where you move one target bone and the 2 bones of the leg are moving accordingly. (so that I can simulate the footsteps only by moving one target bone, instead of the 2 bones, but if I don't find a way, I will just manually change each bone for each leg).
     

    Attached Files:

    • 2.png
      2.png
      File size:
      32.9 KB
      Views:
      591
  4. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    the bone with the full circle are mandatory, the other one are optionnal so both spine2 and chest are optionnal. so it should not matter in your case. It look like you have some translation animation occuring on your bone, it may lower the retargeting quality if you plan to reuse the same animation on different humanoid character.

    So to get something like this you need to use IK on foot
    https://docs.unity3d.com/ScriptReference/Animator.SetIKPosition.html
    https://docs.unity3d.com/ScriptReference/Animator.SetIKPositionWeight.html

    If you are not familiar with IK you should look for some tutorial on youtube.
     
  5. ReignRavel

    ReignRavel

    Joined:
    Apr 20, 2017
    Posts:
    26
    Thanks, could you help me making this work? I sent my character on pasteall here ( I put the translation of the chest to 0, but I don't see any scale translation, so the import message is only saying something about the scale). The preview in Unity (the square at the bottom right) shows the animation, but the scene does not.
    I found this tutorial on youtube (I put the exact second on the link), the guy can move the arrow of an object to test the IK, how is that possible? When I click Play, no object in my scene can be selected and moved with the arrows.
     
  6. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    I don't have blender installed, so i can't import the file, and to fix those warning you need the authoring tool to modify the file.


    If you look closely, you can see that he's using two gameobject's transform in his monobehaviour to drive the ik position.

    Basically just create two gameobject in your scene, assign it to your monobehaviour and then in you're OnAnimatorIK callback you just use transform.position to drive the ik effector position.
    Take a look at the documentation for OnAnimatorIK, there is an example
    https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnAnimatorIK.html
     
  7. ReignRavel

    ReignRavel

    Joined:
    Apr 20, 2017
    Posts:
    26
    I don't have the "arrows" to move the ik targets in Play Mode, maybe there is an option to select them in Play Mode? I tried to move the ik target with the code, but the leg does not follow. Maybe because the rig does not animate at all in the scene.
     
  8. DominoM

    DominoM

    Joined:
    Nov 24, 2016
    Posts:
    460
    Doesn't HumanPoseHandler give you access to tweak muscles directly?
     
  9. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    yes you can use a HumanPoseHandler to read a FK pose, tweak the muscle and the write back a FP pose but this object is not part of the animation evaluation pipeline so you can't tweak the muscle values while the character is been evaluated.
     
  10. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    You need to open and do you're operation in the Scene view, the Game view doesn't have gizmo to manipulate object.
     
    awesomedata likes this.
  11. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    899
    I'm not sure I follow here.

    I've been playing with this for some time now and have a character I'm trying to set his muscle values directly by first calling GetHumanPose to grab his initial T pose in the Start function, then in Update I try to set one of the muscles (the neck muscle, for example) to something different and use SetHumanPose to update the new muscle settings in the Update method, but this doesn't work right since the farther away from the scene origin he is, the weirder things get with his origin (for example, moving his transform doesn't change his position, yet even though he's way away from his bounding box and transform in the scene view, his neck still rotates correctly. Also not sure why this muscle change doesn't work with optimize hierarchy checked).

    Care to explain what's going on here?

    I'm trying to find a way to overshoot a target pose (using custom interpolation) but I'm having a heck of a time making this possible with Mecanim. I thought muscles would be the way to go, but they're proving to be unpredictable and essentially useless. Any ideas on what else I can try?
     
    Last edited: May 27, 2018
  12. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    You will need the new animation jobs system to create your own custom mixer, it the only way you can change the interpolation mode for your blend.
     
  13. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    899
    What kind of code would a custom mixer like that require with the new Jobs system?


    I wasn't really looking to have to rewrite the entire Animation / humanoid system from the ground up just to do simple interpolation curves. Since I currently have Mecanim's "humanoid" component / retargeting and its basic muscle limits already there for me to work with, I was planning to simply leverage those systems and use its existing bone-mappings, retargeting, and muscle constraints for the majority of my pose-changing / blending. Is this still possible?



    Also is there any way planned to be able to easily (and directly) grab poses? I simply wanted to grab a "humanoid pose" with it, then tweak that pose a little, and write it back. This is actually what led me to "GetHumanPose" in the first place.

    Right now I'm just not seeing any easy way to just "grab a pose and change it" without jumping through some major hoops with sampling animations. GetHumanPose seemed to be based on mocap stuff but clearly doesn't seem usable to work as a Mecanim "pose-grabber" that properly preserves both world position and humanoid muscles like I would expect.
     
    Last edited: May 30, 2018
  14. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    3,790
    @Mecanim-Dev
    Is there still no way to access the muscle bend rotations directly from code?

    I was looking through the humanoid avatar scripting and saw that you expose various limits to code. The docs on this stuff is very vague.

    Human trait: https://docs.unity3d.com/ScriptReference/HumanTrait.html
    this gives you access to muscle mapping, kinda. It gives access to muscle name string index.

    Then you gotta look that up against the HumanDescription's name map? https://docs.unity3d.com/ScriptReference/HumanDescription-human.html

    Then you gotta cross reference that against the limits: https://docs.unity3d.com/ScriptReference/HumanLimit.html

    I'm still somewhat confused though because most muscles have two rotation axis, there's usually a bend and a twist, so I need two muscle definitions per bone in most cases.

    Can you give me a clearer idea on how to interpret all of this? I'm trying to replicate the muscle bends outside of mecanim.
     
  15. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,666
    awesomedata likes this.
  16. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    3,790
    Thanks for the response, so to clarify, I'm working on a custom system with physics and ik, I could just hardcode each of the bone rotation limits, but I thought it would be nice to use the definitions from humanoid avatar. It would be even better if I could directly manipulate the joint rotations using the same sliders unity does.

    Ideally, I am not looking to do this in job system (I have deadlines and I wanna get this finished asap), but I can set up tool to copy values if needed.

    So to use this, I would need to set up a custom job as in example, record the min and max values of each muscle rotation, then use that output as reference?

    I just started to write some prototype code to generate the various limits from avatar using
    Animator.avatar.humanDescription.human
    - I should be able to lerp between the muscle limits here, correct? I would need to hardcode the twist vs rotate from the separate min/max axis here manually, since I don't think there's a reference.

    And use the
    Animator.avatar.humanDescription.skeleton
    tpose positions as a reference point for each of those rotations (they are treated as center, i assume?)

    Which approach would you recommend, or is there a better approach elsewhere?
     
  17. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    3,790
    So just for reference, this seems to work in most cases.
    1u0dxYZ6Xg.gif
    Code in this screencap:
    Code (csharp):
    1.  
    2.  
    3. public HumanBodyBones Bone;
    4. [Range(-1,1)]
    5. public float LeftArmAmt = 1;
    6.  
    7. [Range(0,2)]
    8. public int TargetAxis;
    9.  
    10. private void OnValidate(){ SetFromTpose(); }
    11.  
    12. public void SetFromTpose()
    13. {
    14.   EnforceTPose();
    15.   var bone = Animator.GetBoneTransform(Bone);
    16.  
    17.   var limit = GetLimit(Bone);
    18.  
    19.   var angleMin = limit.min[TargetAxis];
    20.   var angleMax = limit.max[TargetAxis];
    21.  
    22.   var ang = Mathf.LerpAngle(angleMin, angleMax, (LeftArmAmt+1)/2f);
    23.   Vector3 f = new Vector3();
    24.   f[TargetAxis] = ang;
    25.  
    26.   bone.localRotation = f.EulerToRotation() * bone.localRotation;
    27. }
    28.  
    This seems to work almost perfectly in most cases - except the upper arm twist as shown here - which seems upsidedown. Assuming my avatar looks pretty good during animation, I don't think this is a problem with the avatar definition (?). Any ideas? Should I not be starting from tpose rotations?

    EDIT: problem was Mathf.LerpAngle, should have been using vanilla lerp, also I don't think an exact lerp is what I want. Zero from fetal is neutral local rotation, not the half point between the upper and lower limit. So it's like

    if( amount < 0 ) Mathf.Lerp( 0, limit.min, -amount);
    if( amount > 0 ) Mathf.Lerp( 0, limit.max, amount);

    Also, 'origin' rotations start from the fetal pose, not tpose.
    For people who might read this later - you can get the fetal pose reference using the sample code found here: https://docs.unity3d.com/2019.3/Documentation/ScriptReference/Animations.MuscleHandle.html

    EDIT2: Sadly, this doesn't actually work right. There's another step to converting the limits into rotations that I'm missing. Doesn't seem like enough data is being exposed to actually do a proper mapping. @Mecanim-Dev would love any insight you could provide (I just spent 10 hours on this and I've gotten nowhere - I just want the rotation ranges)...

    Just to clarify the problem, the limits
    Animator.avatar.humanDescription.human[x].limit

    presented in left upper arm are:

    LeftUpperArm :: X:-90,90, y:-100,100 z:-60,100


    The (-60, 100) matches the muscle settings in arm up down, but to actually match this rotation you need to rotate on the x axis not the z axis, and to fully extend up you need to be at -100 not 100. So this looks like a dead end unless there is a matrix or a mapping I can apply.
     
    Last edited: Jan 15, 2020
unityunity