How to create their your own Humanoid Avatar without fbx importing

You need to have a GameObject hierarchy that matches the avatar hierarchy.
Once you have this, select the Root GameObject and click on the Custom Tools Tab and click Create Human Avatar. A Humanoid Avatar will be generated at the Assets directory. If you need to include additional body parts, add its name to HUMAN_NAMES and its GameObject to the hierarchy.

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

public class AvatarMaker
{
    private static readonly List<string> HUMAN_NAMES = new List<string>()
    {
        "Head",
        "Hips",
        "LeftFoot",
        "LeftHand",
        "LeftLowerArm",
        "LeftLowerLeg",
        "LeftUpperArm",
        "LeftUpperLeg",
        "RightFoot",
        "RightHand",
        "RightLowerArm",
        "RightLowerLeg",
        "RightUpperArm",
        "RightUpperLeg",
        "Spine",
    };

    private static readonly int RECURSION_DEPTH_LIMIT = 50;

    [MenuItem("CustomTools/MakeHumanAvatar")]
    private static void MakeHumanAvatar()
    {
        GameObject activeGameObject = Selection.activeGameObject;

        if (activeGameObject != null)
        {
            var numHumanBones = HUMAN_NAMES.Count;
            HumanBone[] humanBones = new HumanBone[numHumanBones];
            for (var i = 0; i < numHumanBones; i++)
            {
                var humanName = HUMAN_NAMES[i];
                humanBones[i] = new HumanBone
                {
                    boneName = humanName,
                    humanName = humanName
                };
                humanBones[i].limit.useDefaultValues = true;
            }

            var skeletonBones = new SkeletonBone[numHumanBones + 1];
            skeletonBones[0] = new SkeletonBone
            {
                name = "Root",
                position = Vector3.zero,
                rotation = Quaternion.identity,
                scale = Vector3.one
            };

            for (var i = 0; i < numHumanBones; i++)
            {
                var humanName = HUMAN_NAMES[i];
                BoneOffsetFromRoot(
                    activeGameObject,
                    humanName,
                    out var position,
                    out var rotation,
                    out var scale
                );

                skeletonBones[i + 1] = new SkeletonBone
                {
                    name = humanName,
                    position = position,
                    rotation = rotation,
                    scale = scale
                };
            }

            var humanDescription = new HumanDescription
            {
                upperArmTwist = 0.5f,
                lowerArmTwist = 0.5f,
                upperLegTwist = 0.5f,
                lowerLegTwist = 0.5f,
                armStretch = 0.5f,
                legStretch = 0.5f,
                feetSpacing = 0.0f,
                hasTranslationDoF = false,
                human = humanBones,
                skeleton = skeletonBones
            };

            Avatar avatar = AvatarBuilder.BuildHumanAvatar(activeGameObject, humanDescription);
            avatar.name = activeGameObject.name;
            Debug.Log(avatar.isHuman ? "is human" : "is generic");

            var path = string.Format("Assets/{0}.ht", avatar.name.Replace(':', '_'));
            AssetDatabase.CreateAsset(avatar, path);
        }
    }

    private static void BoneOffsetFromRoot(
        GameObject rootGameObject,
        string boneName,
        out Vector3 position,
        out Quaternion rotation,
        out Vector3 scale
    )
    {
        Debug.Log(boneName);
        var boneTransform = RecursiveFindChild(rootGameObject.transform,boneName);
        var boneLocalPosition = boneTransform.transform.localPosition;
        var boneLocalRotation = boneTransform.transform.localRotation;
        var boneLocalScale = boneTransform.transform.localScale;


        GameObjectOffsetFrom(
            rootGameObject.transform,
            boneTransform,
            in boneLocalPosition,
            in boneLocalRotation,
            in boneLocalScale,
            out position,
            out rotation,
            out scale,
            0
        );
    }

    private static void GameObjectOffsetFrom(
        Transform ancestorTransform,
        Transform gameObjectTransform,
        in Vector3 inputPosition,
        in Quaternion inputRotation,
        in Vector3 inputScale,
        out Vector3 position,
        out Quaternion rotation,
        out Vector3 scale,
        int recursionDepth
    )
    {
        if(recursionDepth > RECURSION_DEPTH_LIMIT)
        {
            throw new UnityException(
                "Making a human avatar failed due to incorrect" +
                " structure of the GameObject's hierarchy"
            );
        }

        if(ancestorTransform == gameObjectTransform)
        {
            position = inputPosition;
            rotation = inputRotation;
            scale = inputScale;
            return;
        }
        else
        {
            var parentTransform = gameObjectTransform.parent;
            var newPosition = inputPosition + parentTransform.localPosition;
            var newRotation = inputRotation * parentTransform.localRotation;
            var newScale = inputScale;
            newScale.Scale(parentTransform.localScale);
            GameObjectOffsetFrom(
                ancestorTransform,
                parentTransform,
                in newPosition,
                in newRotation,
                in newScale,
                out position,
                out rotation,
                out scale,
                recursionDepth
            );
            return;
        }
    }

    private static Transform RecursiveFindChild(Transform parent, string childName)
    {
        foreach (Transform child in parent)
        {
            if (child.name.Equals(childName))
            {
                return child;
            }
            else
            {
                Transform found = RecursiveFindChild(child, childName);
                if (found != null)
                {
                    return found;
                }
            }
        }
        return null;
    }
}
1 Like

Great! Awsome!

Super Cool!