Open bsgg opened 5 years ago
Thank you for reporting this issue!
Currently, this is by design, as completely skipping bones can be a bit tricky, especially on the playback side, so even with enforceHumanoidBones it will still include other bones inbetween. I guess the name does not quite reflect this, so it should probably be renamed until this functionality is fully implemented.
Thanks for answer so quickly
Just for myself (for now I only intended to use the tool with humanoid bones) I implemented a quick fix (It's not a proper solution just somethin quick for now). In your class BVHAnimationLoader, I added an extra dictionary. As a key for the dictionary I use the enum HumanBodyBones as as string, and as a value I have a struct where with 2 members. the HumanBodyBones enum and the transform.
public struct StandardHumanoidBone { // Id bone public HumanBodyBones BoneIndex; public Transform TransformBone; }
private Dictionary<string, StandardHumanoidBone> retargetBonesMap;
I added the a public function to initialize this function, and all I do is populate the dictionary with Transform bone = targetAvatar.GetBoneTransform(boneIndex);
(nothing out of ordinary)
In the method getCurves, I commented the line
Transform nodeTransform = getBoneByName(node.name, bone, first);
and use my dictionary to get the nodeTransform
if (retargetBonesMap.ContainsKey(node.name)) { nodeTransform = retargetBonesMap[node.name].TransformBone; }
After this I need to check if this nodeTransform is null to avoid null references later in your code.
For now I am only interested in humanoid bones, so this is not adecuate for your tool since you support "both options", but here is a quick idea to "fix" this.
I also implemented another fix on the BvhRecorder, I added a recursive function to skip bones that are not standard unity humanoid
**private void buildHumanoidSkeleton(SkelTree currentParentJoint, Transform currentBone, bool isBoneRoot = false) { SkelTree nextParentJoint;
if (!isBoneRoot)
{
HumanBodyBones tBone = HumanBodyBones.LastBone;
if (IsStandardHumanoidBone(currentBone, out tBone))
{
SkelTree childBone = new SkelTree(currentBone, boneMap);
currentParentJoint.children.Add(childBone);
nextParentJoint = childBone;
}
else
{
nextParentJoint = currentParentJoint;
}
}else
{
nextParentJoint = currentParentJoint;
}
// Get childs
if (currentBone.childCount > 0)
{
for (int i = 0; i < currentBone.childCount; i++)
{
buildHumanoidSkeleton(nextParentJoint, currentBone.GetChild(i));
}
}
}**
I added this function to check if the bone is standard **private bool IsStandardHumanoidBone(Transform bone, out HumanBodyBones boneType) { boneType = HumanBodyBones.LastBone;
for (int i=0; i<(int)HumanBodyBones.LastBone; i++ )
{
HumanBodyBones indexBone = (HumanBodyBones)i;
Transform humanoidBone = targetAvatar.GetBoneTransform(indexBone);
if (humanoidBone == bone)
{
boneType = indexBone;
return true;
}
}
return false;
}**
I use this function in buildSkeleton when enforceHumanoidBones is true
if (enforceHumanoidBones) { buildHumanoidSkeleton(skel, rootBone, true); }
I hope this helps
Thank you for the details! I will look into adding something like this when I have time.
Thanks for answer so quickly
Just for myself (for now I only intended to use the tool with humanoid bones) I implemented a quick fix (It's not a proper solution just somethin quick for now). In your class BVHAnimationLoader, I added an extra dictionary. As a key for the dictionary I use the enum HumanBodyBones as as string, and as a value I have a struct where with 2 members. the HumanBodyBones enum and the transform.
public struct StandardHumanoidBone { // Id bone public HumanBodyBones BoneIndex; public Transform TransformBone; }
private Dictionary<string, StandardHumanoidBone> retargetBonesMap;
I added the a public function to initialize this function, and all I do is populate the dictionary with Transform bone = targetAvatar.GetBoneTransform(boneIndex);
(nothing out of ordinary)
In the method getCurves, I commented the line
Transform nodeTransform = getBoneByName(node.name, bone, first);
and use my dictionary to get the nodeTransform
if (retargetBonesMap.ContainsKey(node.name)) { nodeTransform = retargetBonesMap[node.name].TransformBone; }
After this I need to check if this nodeTransform is null to avoid null references later in your code.
For now I am only interested in humanoid bones, so this is not adecuate for your tool since you support "both options", but here is a quick idea to "fix" this.
I also implemented another fix on the BvhRecorder, I added a recursive function to skip bones that are not standard unity humanoid
**private void buildHumanoidSkeleton(SkelTree currentParentJoint, Transform currentBone, bool isBoneRoot = false) { SkelTree nextParentJoint;
if (!isBoneRoot) { HumanBodyBones tBone = HumanBodyBones.LastBone; if (IsStandardHumanoidBone(currentBone, out tBone)) { SkelTree childBone = new SkelTree(currentBone, boneMap); currentParentJoint.children.Add(childBone); nextParentJoint = childBone; } else { nextParentJoint = currentParentJoint; } }else { nextParentJoint = currentParentJoint; } // Get childs if (currentBone.childCount > 0) { for (int i = 0; i < currentBone.childCount; i++) { buildHumanoidSkeleton(nextParentJoint, currentBone.GetChild(i)); } } }**
I added this function to check if the bone is standard **private bool IsStandardHumanoidBone(Transform bone, out HumanBodyBones boneType) { boneType = HumanBodyBones.LastBone;
for (int i=0; i<(int)HumanBodyBones.LastBone; i++ ) { HumanBodyBones indexBone = (HumanBodyBones)i; Transform humanoidBone = targetAvatar.GetBoneTransform(indexBone); if (humanoidBone == bone) { boneType = indexBone; return true; } } return false; }**
I use this function in buildSkeleton when enforceHumanoidBones is true
if (enforceHumanoidBones) { buildHumanoidSkeleton(skel, rootBone, true); }
I hope this helps
Hello,I've made this work, I record muscles and root motion,but current I have no idea to build a animationClip but play it at runtime.Any idea?
Any update on this?
@bsgg hi, how do you "record with 1 model the motion capture and use a different (or several) model to play the animation. "?
I try to implement this function by following code according readme file, but it fails(there are two errors in ellipse):
Any idea will be appreciated !
Great tool! It works nice and it is saving me a lot of time.
I think I found a mistake on your code but I'm not so sure. I am testing you tool with models from mixamo website. So far so good, I was able to export some animations, check them on blender, and reproduced in unity at runtime. But I have some problems, I am tryingo to use different models with a Humanoid configuration. My idea is to record with 1 model the motion capture and use a different (or several) model to play the animation. Eveytime I record I use the option enforceHumanoidBones, to record with humanoid unity bones. If I use the same model to play the record, it works, but with different models is not always the case. I don't know if this has a solution.
Now, one of the things I saw on your code, is what I think a small bug. the function buildSkeleton, on BVHRecorder script, when you are creating the skel tree with the possible bones, you are not taking into account if someone whants to use enforceHumanoidBones. In some cases there are extra bones on the bvh file that are not suppose to be there. Reading your code I know you are adding those bones withouth checking if they are humanoidbones. I know this happens because I tested with one of the models from mixamo and in the exported file I had the bone Neck1 which is not part of Unity HumanBodyBones enumerated
I hope this helps to improve the tool.