Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity 3D - Move Humanoid head muscles using script

Tags:

unity3d

Goal

I would like to rotate a head of a humanoid character given x, y, z rotation values using a script (without using any other object in the scene as "look" direction).

What I want to do

When setting-up the rigging of a Humanoid character (humanoid prefab --> Rig --> Animation Type: Humanoid --> Configure --> Muscles & Settings), you see the following interface: https://docs.unity3d.com/Manual/MuscleDefinitions.html

In this menu, under Head, you can drag a slider to move e.g. your humanoid head up and down. I want to achieve the same with a script, but I don't know how to do this.

Resources

This question never received a proper answer with example code: https://answers.unity.com/questions/824628/can-we-using-script-to-moving-the-muscles-in-unity.html

I presume I have to do something with HumanPose.muscles (https://docs.unity3d.com/ScriptReference/HumanPose-muscles.html), however with the lack of code samples, I have no idea how to approach this.

Edit 3: This link has a code sample for HumanPose, but I didn't get it to work yet: https://forum.unity.com/threads/humanposehandler.430354/

Question

How to get the head muscles of a humanoid character and rotate them by giving values through a script? (Or any other way how to rotate the head using head rotation values, without another object in the scene). Any help would be appreciated.

Edit 1 & 2: Sample code

I receive a JSON formatted message from which I extract the radian values and change it into degrees:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json.Linq;  // JSON reader; https://assetstore.unity.com/packages/tools/input-management/json-net-for-unity-11347

public class HeadRotator : MonoBehaviour {

    Quaternion rotation = Quaternion.identity;

    // Radians to degree
    float Rad2Degree = 180 / Mathf.PI;

    // Human muscle stuff
    HumanPoseHandler humanPoseHandler;
    HumanPose humanPose;
    Animator anim;
    //Transform head;

    // Use this for initialization
    void Start () {
        // get attached Animator controller
        anim = GetComponent<Animator>();

        //head = anim.GetBoneTransform(HumanBodyBones.Head);
        //Debug.Log (head);
    }


    // Use JSON message to set head rotation and facial expressions;
    // IEnumerator to run in main thread (needed for SetBlendShapeWeight)
    public IEnumerator RequestHeadRotation(JObject head_pose)
    {
        // rotate head of character with received x, y, z rotations in radian
        List<float> head_rotation = new List<float> ();
        foreach (KeyValuePair<string, JToken> pair in head_pose) {
            //Debug.Log(pair);
            // store head rotation in degrees
            head_rotation.Add(float.Parse(pair.Value.ToString())*Rad2Degree*10);
        }

        Debug.Log ("" + head_rotation[0] + ", " + head_rotation[1] + ", " + head_rotation[2]);
        //Quaternion rotation = Quaternion.Euler(new Vector3(head_rotation[0], head_rotation[1], head_rotation[2]));
        //Debug.Log ("" + rotation[0] + ", " + rotation[1] + ", " + rotation[2] + ", " + rotation[3]);
        // head.Rotate (rotation);

        // https://docs.unity3d.com/ScriptReference/Quaternion-eulerAngles.html
        rotation.eulerAngles = new Vector3 (head_rotation[0], head_rotation[1], head_rotation[2]);

        // Animator.GetBoneTransform()
        anim.SetBoneLocalRotation(HumanBodyBones.Head, rotation);

        yield return null;
    }
}
  • Head rotation data: 3.208564, 0.4583662, 0.1145916
  • Quaternion data: 0.0280001, 0.003970424, 0.0008876149, 0.9995997

I don't really know well how to set either the head bone or the muscles. Most examples provide only a snippet of the code, so I'm struggling in figuring out how it works.

Edit 2: I feel I'm getting close, but anim.SetBoneLocalRotation(HumanBodyBones.Head, rotation); seems to get ignored.

Edit 4: I put on Github a simple version of my head rotation attempt: https://github.com/NumesSanguis/Basic-Unity-Head-Rotation

like image 439
NumesSanguis Avatar asked Jan 28 '23 16:01

NumesSanguis


1 Answers

After testing for a while, I figured it out.

  1. Firstly, set the animator to IK Pass.

enter image description here

  1. Then use SetBoneLocalRotation inside OnAnimatorIK method. You can know more about this method here: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnAnimatorIK.html
    Following is the modified code that worked for me

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HeadRotator : MonoBehaviour
{
	public Vector3 rot = new Vector3(20, 30, 10);
	Animator anim;

	//  Bone stuff
	Transform head;

	//  !!! Head bone rotation approach !!!
	void Start () {
	  	// get attached Animator controller
		anim = GetComponent<Animator>();
		head = anim.GetBoneTransform(HumanBodyBones.Head);
	}

	void OnAnimatorIK (int layerIndex) {
		print ("OnAnimatorIK - running");
		anim.SetBoneLocalRotation(HumanBodyBones.Head, Quaternion.Euler(rot));
	}
}
like image 199
ZayedUpal Avatar answered Jan 31 '23 20:01

ZayedUpal