Unity5: Move Humanoid's Bones Interactively with C# Program


2017.08.02: created by
2017.08.04: revised by
[Up] Japanese English

Prerequisite knowledge


Unity5: Rotate Humanoid's Bones on the coordinate axis of the local coordinate system

Runtime Video Humanoid2.mp4


  1. Use the Unity's project Humanoid.zip craeted in "Unity5: Move Humanoid's Bones Directly with C# Program".
  2. In the explanation below, we expands "Humanoid.zip" and changed the name of the folder to "Humanoid2/". Open this folder with Unity.

  3. There are two scene files under "Assets/Scenes/" in the project window. Once open the "rig.unity" scene file, and save it as "rig3.unity" immediately.
  4. Right click on "Assets/Scripts" in the Project window, and create C# Scripts ( -> Create -> C# Script). Rename it as "RigControl3".






  5. Define the enum type "enum Bone" and declare the variable "bone" of this type as public. By writing like this, you make an item called "Bone" in the "Rig Control 3 (Script)" component displayed in the inspector window of the Unity Editior so that you can change the bone to be operated with the popup menu while executing the program.

    In Unity, Bone is specified by the "HumanBodyBOnes.BoneName". Therefore, you need to define a conversion from an "enum Bone" type defined here to HumanBodyBones type in Unity. The variable bodyBones defines the mapping.

    We use Enum.GetValues() function to operate on all the elements of the "enum Bone", but to use Enum we need to declare "import Syste;" at the beginning of the program.

    In this program, We use the offset(float,float,float,float) method of the RigBone class to add rotation to the initial value of each Bone. The RigBone class is defined in "Assets/Scripts/RigBone.cs" in the project window.

    RigControl3.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System;
    
    public class RigControl3 : MonoBehaviour {
      public enum Bone {
        Hips,
        Spine,
        Chest,        // optional
        UpperChest,   // optional
        Neck,         // optional
        Head,
        LeftShoulder, // optional
        LeftUpperArm,
        LeftLowerArm,
        LeftHand,
        LeftUpperLeg,
        LeftLowerLeg,
        LeftFoot,
        RightShoulder, // optional
        RightUpperArm,
        RightLowerArm,
        RightHand,
        RightUpperLeg,
        RightLowerLeg,
        RightFoot
      }
      private Dictionary<Bone,HumanBodyBones> bodyBones = new Dictionary<Bone,HumanBodyBones>() {
        { Bone.Hips, HumanBodyBones.Hips },
        { Bone.Spine, HumanBodyBones.Spine },
        { Bone.Chest, HumanBodyBones.Chest },
        { Bone.UpperChest, HumanBodyBones.UpperChest },
        { Bone.Neck, HumanBodyBones.Neck },
        { Bone.Head, HumanBodyBones.Head },
        { Bone.LeftShoulder, HumanBodyBones.LeftShoulder },
        { Bone.LeftUpperArm, HumanBodyBones.LeftUpperArm },
        { Bone.LeftLowerArm, HumanBodyBones.LeftLowerArm },
        { Bone.LeftHand, HumanBodyBones.LeftHand },
        { Bone.LeftUpperLeg, HumanBodyBones.LeftUpperLeg },
        { Bone.LeftLowerLeg, HumanBodyBones.LeftLowerLeg },
        { Bone.LeftFoot, HumanBodyBones.LeftFoot },
        { Bone.RightShoulder, HumanBodyBones.RightShoulder },
        { Bone.RightUpperArm, HumanBodyBones.RightUpperArm },
        { Bone.RightLowerArm, HumanBodyBones.RightLowerArm },
        { Bone.RightHand, HumanBodyBones.RightHand },
        { Bone.RightUpperLeg, HumanBodyBones.RightUpperLeg },
        { Bone.RightLowerLeg, HumanBodyBones.RightLowerLeg },
        { Bone.RightFoot, HumanBodyBones.RightFoot }
      };
      public GameObject humanoid;
      public Vector3 bodyRotation = new Vector3(0,0,0);
      public Bone bone = Bone.LeftUpperArm;
      public float angle = 0;
      public float axisX = 0.0f;
      public float axisY = 1.0f;
      public float axisZ = 0.0f;
      Dictionary <Bone,RigBone> rigBones;
      void Start () {
        rigBones = new Dictionary <Bone,RigBone>();
        foreach (Bone b in Enum.GetValues(typeof(Bone))) {
          rigBones.Add(b, new RigBone(humanoid, bodyBones[b] ));
        }
      }
      void Update () {
        if (rigBones[bone].isValid == false) return;
        rigBones[bone].offset(angle,axisX,axisY,axisZ);
        humanoid.transform.rotation 
          = Quaternion.AngleAxis(bodyRotation.z,new Vector3(0,0,1))
          * Quaternion.AngleAxis(bodyRotation.x,new Vector3(1,0,0))
          * Quaternion.AngleAxis(bodyRotation.y,new Vector3(0,1,0));
      }
    }
    
  6. Select "RigController" in the Hierarchy window and then Remove Component the "Rig Control (Script)" component in the Inspector window.
  7. Settings  of Rig Control (Script) -> Remove Component
    



  8. Drag "Assets/Scripts/RigControl2" in the Project window onto the the Hierarchy's "RigController" and drop it with the "RigController" surrounded by a blue ellipse.



  9. Select "RigController" in the Hierarchy window, the "Rig Control 2 (Script)" component is now displayed in the Inspector window, so you can see that it was added. Set the Humanoid character ("AsianBoy" in this example) to the "Game Object" in this component.



  10. Click to execute this program.
  11. Select some bones and set values in this situation. In order to set up properly I recommend the following way.

    1. Select a bone.
    2. Set the Angle value to 0.
    3. Change the X, Y, Z value of Axis.
    4. Set the Angle to the value you want.
    By operating like this, you can rotate the Bone with the Angle around the axis specified in the local coordinate system of that Bone .







    When BodyRotation is set to (X,Y,Z)=(0,180,0), Humanoid points to camera direction. The one who operated in this state may be easier to grasp the image.




    [Notice] The Bone enumerated type defined in "RigControl3.cs" also includes "optional Bone" in Unity's Animator. Therefore, depending on the used Humanoid data, some errors may be generated at the time of execution in trying to acquire the Transform of optional Bone not assigned. In such a case, comment out the optional Bone (which are specified as "// optional") from the definitiona of the enum Bone.

  12. Save the scene.
  13. "rig3.unity" has been already creaetd, so overwrite it.

    File -> Save Scenes
    
  14. The described Unity's project file is here Humanoid2.zip.

Check the Orientation of Local Coordinate Axes in Each Bone

Unity's coordinate system is left-handed. In the left-handed coordinate system, the positive rotate direction about each axis is "clockwise when looking at the origin from infinity of its axis".

Positive Rotate Direction Around Each Axis

In each Bone, you can see the orientation of the X-axis of its local coordinate system (i.e. Transform) by increasing the value of Angle in the state of (Axis X, Axis Y, Axis Z) = (1, 0, 0). Similarly, you can see the orientation of the Y-axis in the state of (Axis X, Axis Y, Axis Z) = (0, 1, 0), and the orientation of the Z-axis in the state of (Axis X, Axis Y, Axis Z) = (0, 0, 1). The following figure shows the result of examining the axes of rotation of each bone by repeating this procedure.





Yoshihisa Nitta

http://ynitta.com/