I’ve been working on a runtime clothing system for my 3d project. I am able to replace the clothes, but when I try to update the avatar via script during runtime it breaks animations. The error shows that it is trying to map a transform that doesn’t exist in the the avatar for the clothing pack (which makes sense since I have added additional Game Objects to the player character that don’t exist in any clothing pack avatar). However, when I drag and drop the avatar into the animator via the editor it works perfectly.
Does anyone know why it tries to map other transforms when updating via script, but doesn’t have an issue when I drag and drop? All avatars are humanoid and avatar.isValid returns true.
So I ended up fixing it for what I needed. I found this post GitHub - bkevelham/unity-avatar-generation: A minimal example of how to use Unity's AvatarBuilder.BuildHumanAvatar API. which gave more information on using AvatarBuilder.BuildHumanAvatar(go, humanDescription). There’s a section on the page that mentions using different avatars if the bones should be rotated or elongated, but it follows the same logic. You need to use a fresh HumanDescription. I’m still not entirely sure why my change fixed it, but leaving my solution here in case someone else comes across a similar issue.
So my issue was that when I was using AvatarBuilder.BuildHumanAvatar(), the human description I was passing was causing the avatar assignment to look at all of the transforms in the current hierarchy, not just the ones defined in the HumanBone hierarchy. I thought the human description I was using would suffice because all of my fbx files/avatars use an identical bone structure. I guess since there are additional child gameObjects of the root with the animator I wanted to update, it wanted to know how those should be mapped since they don’t show up in the original avatar. For some reason, making a fresh HumanDescription and duplicating the skeleton avoids this. I made a simple method that duplicates the public fields of the human description if you want it.
private HumanDescription duplicateHumanDescription(HumanDescription oldHD) {
HumanDescription newHD = new HumanDescription();
newHD.human = oldHD.human;
newHD.skeleton = oldHD.skeleton;
newHD.armStretch = oldHD.armStretch;
newHD.feetSpacing = oldHD.feetSpacing;
newHD.lowerArmTwist = oldHD.lowerArmTwist;
newHD.lowerLegTwist = oldHD.lowerLegTwist;
newHD.upperArmTwist = oldHD.upperArmTwist;
newHD.upperLegTwist = oldHD.upperLegTwist;
newHD.hasTranslationDoF = oldHD.hasTranslationDoF;
return newHD;
}
I’m still not entirely sure why the original HumanDescription causes the avatar assignment to look at all of the transforms, even ones that don’t participate in the human skeleton hierarchy, but using a fresh HumanDescription and duplicating worked for me.
TLDR: If you want to swap your humanoid avatar at runtime and there are additional gameObject in your destination hiearchy that don’t participate in the bone structure for animations… create a fresh HumanDescription, copy the values from your source avatar.HumanDescription into your new HumanDescription, build your Avatar using AvatarBuilder.BuildHumanAvatar(go, humanDescription), then assign your new avatar to the animator.