Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more..
    Dismiss Notice
  3. Dismiss Notice

Transform hierarchy does not match: Transform 'Armature' not found in HumanDescription.

Discussion in 'Animation' started by Lorin_Atzberger, Oct 20, 2021.

  1. Lorin_Atzberger

    Lorin_Atzberger

    Joined:
    Dec 11, 2013
    Posts:
    118
    Hello,

    I have a nice character customization system made with legacy animations which I'm trying to port to mecanim now but I'm having some issue.
    My setup is like this:
    I use Blender to create the character armature and multiple meshes that are all attached to the same armature and share the same animations. The hierarchy looks like this in blender:
    BlenderHierarchy.PNG

    I export every mesh as a standalone, including all the bones but no animations. Here is a snip of the hierarchy of a mesh:
    MeshHierarchy.PNG

    Note that the object that ends up having the skinned mesh modified is the child "Arms" since the root one is just a game object that serves as the parent. The "Armature" is the exact same hierarchy as the bones in blender.

    I also export the animations as a separate file with no meshes in it. This is the hierarchy that appears in unity:
    AnimationsHierarchy.PNG
    All the objects there are the contents of the Armature.

    This step is not relevant as far as I can tell but I include it for completeness: After all the meshes are exported, I have a pipeline that takes all the meshes in the game and performs atlassing, generating new materials and new fbx files that all share the same texture. I also generate more meshes that I get as an input since I have texture variations for a lot of the meshes (different races, different clothes, etc) The resulting fbx files have no other difference than the uvs being different (retargeted to the atlas texture).

    The next part happens during the runtime. The game combines all the meshes needed for a character in one which works well since they all share the same texture and can be handled in one drawcall. For this I use the CombineMeshes api after which I copy the bindposes.

    This all works very well but as I said, I'd like to move to mecanim in order to have some nicer transitions and handle some things in the animation controller.

    If I create an avatar using the animations file and then go to all of the meshes and tell them to use the same avatar I will get an error saying:
    Copied Avatar Rig Configuration mis-match. Transform hierarchy does not match: Transform 'Armature' not found in HumanDescription.
    I kind of understand why this is happening, since the hierarchy is not exactly the same but given how blender handles armatures I'm not sure of a different way of doing this.
     
  2. decoyocelot

    decoyocelot

    Joined:
    Dec 22, 2014
    Posts:
    6
    hi ,were you able to solve this problem ? im having the same aswell
     
  3. Lorin_Atzberger

    Lorin_Atzberger

    Joined:
    Dec 11, 2013
    Posts:
    118
    Yes I did, sort of. My animations file has an avatar, and uses mecanim, while the model files seem to have animation type set to legacy. I'm not really sure why I have the meshes as animated since they do not contain any animation data but I'm not at a point where I can easily investigate.

    Still, here's the code that merges the meshes together in my case:
    Code (CSharp):
    1.  
    2.     public static GameObject CombineSkinnedObjects(Transform parent, List<GameObject> prefabs, string name)
    3.     {
    4.         var mesh = new Mesh();
    5.         var combineInstances = new List<CombineInstance>();
    6.         var boneCount = -1;
    7.         foreach(var obj in prefabs)
    8.         {
    9.             var r = obj.GetComponentInChildren<SkinnedMeshRenderer>();
    10.             var inst = new CombineInstance { mesh = r.sharedMesh };
    11.             combineInstances.Add(inst);
    12.  
    13.             if(boneCount==-1)
    14.                 boneCount = r.bones.Length;
    15.             else if(boneCount!=r.bones.Length)
    16.             {
    17.                 Debug.LogError($"Bone count of {obj.name} is different: {r.bones.Length} vs {boneCount}");
    18.                 return null;
    19.             }
    20.         }
    21.         mesh.CombineMeshes(combineInstances.ToArray(), true, false, false);
    22.         var boneWeights = mesh.boneWeights;
    23.         for(var i=0;i<boneWeights.Length;++i)
    24.         {
    25.             boneWeights[i].boneIndex0 %= boneCount;
    26.             boneWeights[i].boneIndex1 %= boneCount;
    27.             boneWeights[i].boneIndex2 %= boneCount;
    28.             boneWeights[i].boneIndex3 %= boneCount;
    29.  
    30.         }
    31.         mesh.boneWeights = boneWeights;
    32.         var sourceMesh = prefabs[0].GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh;
    33.         mesh.bindposes = sourceMesh.bindposes;
    34.  
    35.         var result = Object.Instantiate(prefabs[0], parent);
    36.         var renderer = result.GetComponentInChildren<SkinnedMeshRenderer>();
    37.         renderer.gameObject.name = "Mesh";
    38.         renderer.sharedMesh = mesh;
    39.         result.name = name;
    40.         return result;
    41.     }
    Using this function I build my meshes like this:

    Code (CSharp):
    1. var root = Utils.CombineSkinnedObjects(parent, objects, "Colonist");
    2. Object.Destroy(root.GetComponent<Animation>());
    3.  
    4. var mr = root.transform.GetChild(1).GetComponent<SkinnedMeshRenderer>();
    5.        
    6. var animator = root.transform.GetChild(0).gameObject.AddComponent<Animator>();
    7. animator.runtimeAnimatorController = Game.Database.colonists.visuals.controller; // These are basically globals
    8. animator.avatar = Game.Database.colonists.visuals.avatar;
    9. animator.Rebind();