BVHTools icon indicating copy to clipboard operation
BVHTools copied to clipboard

Issue with BVHRecording when rootBone is set.

Open blueshark27 opened this issue 2 years ago • 3 comments

This is a great tool, thanks for sharing it.

I am going to use this tool for recoding avatar motion and export is as bvh file. In the editor I was setting the avatar and the root bone. For setting the bones I pressed the editor button. In the list all bones except the root bone appeared. With missing root bone in the bone list, all bones below (here the legs) were not exportet.

Adding the root bone manually into the list creates a good resut.

My question is now, why is the root bone not in the list. Is that on purpose? This happends in the function below.

    public void getBones() {
        getTargetAvatar();

        if (enforceHumanoidBones) {
            populateBoneMap(out boneMap, targetAvatar);
        }

        List<Component> meshes = new List<Component>(targetAvatar.GetComponents<SkinnedMeshRenderer>());
        meshes.AddRange(targetAvatar.GetComponentsInChildren<SkinnedMeshRenderer>(true));
        
        HashSet<Transform> boneSet = new HashSet<Transform>();

        foreach (SkinnedMeshRenderer smr in meshes) {
            foreach (Transform bone in smr.bones) {
                Debug.Log("smr.bones: " + bone.name);
                if (rootBone == null || (bone.IsChildOf(rootBone) && bone != rootBone)) {
                    if (enforceHumanoidBones) {
                        if (boneMap.ContainsKey(bone)) {
                            boneSet.Add(bone);
                        }
                    } else {
                        boneSet.Add(bone);
                    }
                }
            }
        }
        
        bones = boneSet.OrderBy(bone => bone.name).ToList();
    }

For my particular case I had to change the if-condition, which is checking for root bone.

blueshark27 avatar Feb 02 '22 13:02 blueshark27

Hi!

It has been a while so I'm a bit fuzzy about the details, but the root bone is used as the root for the SkelTree, so it gets recorded even if it is not part of the bones list. There probably was some reason it is not added to the bones list, but I can't quite remember it.

In any case, I'm not sure why it being missing would cause the legs to end up being missing somehow. Does the armature of your model have an unusual structure, like the legs not being children of the hip bone?

emilianavt avatar Feb 02 '22 13:02 emilianavt

I am using an avatar from mixamo.com. So it has a regular human bone structure.

Checking the code I found, that Skeleton() is always calling getRootBone(targetAvatar, bones);, even when the root is already set. If a list of bones is passed to that function, only the bones in that list are considered. Since this list does not contain the actually root bone, the root bone will be overwritten.

I don't know if I got anything wrong or if that particular behaviour was considered. But in my case, given root bone but not bone list, it leads to a wrong (internal) root, which again leads to the problem I described above.

So my current workaround in buildSkeleton() is putting an if-condition outside the call of getRootBone(targetAvatar, bones).

        if (rootBone == null) {
            rootBone = getRootBone(targetAvatar, bones);
            if (rootBone == null) {
                throw new InvalidOperationException("No root bone found.");
            }
        }

(Maybe I should add a sanity check for given root)

blueshark27 avatar Feb 02 '22 14:02 blueshark27

It's quite odd that it would cause issues. I believe I have used the code to record a number of animations without missing legs before. When I have some time, I'll try looking into it a bit deeper.

For now, as long as your modification works for you that should be fine.

emilianavt avatar Feb 03 '22 22:02 emilianavt