Swapping out a skinned mesh with another skinned mesh

I have a project where I wanted to swap out parts of a skinned mesh on the fly. Users would be able to add a mesh to the scene and have that be parented to the rig. Think changing a characters hair model, or parts of their clothing. You can assume that the meshes used replace the existing meshes are properly weight painted.

We’ve started by trying to clone a mesh from the model, remove the original from the scene, and then add the clone back into it’s old position. The problem is that when we make the clone, it loses all it’s skeletal information.

What can we do to maintain the skeletal data of our clone? Do we have to include the entire rig with the part we want to replace, or can we just include the bones we care about?

I can’t provide the code as it is proprietary, but let me know if any other information would help.

Thanks

*EDIT:

Here’s a code demo https://github.com/sotrh/threejs-skinned-mesh.

Reading up on SkeletonUtils, it seems that SkeletonUtils.clone() needs the bone structure to be in the node getting cloned. I’m not sure how to attach a SkinnedMesh to the skeleton. I’m thinking of copying the skeleton and then using SkeletonUtils.retarget() to “attach” the new mesh.

I am currently experimenting with skeleton, bone and skinned mesh. However, not with models, but with functionally generated geometries.

I am merging different geometries. However, instead of using the predefined geometries and the built-in merging, I use my own variants to realize specific things. For this I look at the object type: “SkinnedMesh”, in the console.

const mesh = new THREE.SkinnedMesh( linkedGeometry, materials );  
console.log( mesh );

I’m still at the beginning there, but think that it is possible to manipulate here and will try it. It’s best to start with simple geometries (or simple models).
Example of how to use CCDIkSolver with a generic SkinnedMesh? - #14 by hofk

Such manipulations are of course much easier with geometry only.

@hofk so looking at your code, it seems that you’re generating the weights manually right? I’d like to avoid that if possible, as our client wants to use more complex models (think hats).

Regardless, I’ll take a deep look at your code to see if I can adapt anything to our use case.

Thanks!

colud you resolve the problem?

So the solution is that the mesh you want to swap in needs to have the same skeletal structure as the main rig. You’ll copy over the skeleton property from the original skinned mesh to the new one.

If your skelatal structure differs, you’ll have to map the bones in the new mesh to bones in the target rig.

2 Likes

If your skelatal structure differs, you’ll have to map the bones in the new mesh to bones in the target rig

Could you please elaborate more how do you map bones? I’m a bit confused about where does Three.js define the weighting/mapping of the mesh to the bones itself.

map origin bones:
boneMap = {}
node.traverse((child) => {
if (child.isBone)
{
boneMap[child.name] = child
}
});

load new skinned mesh from gltf:
scene.add(gltf.scene);
… traverse
var skinnedmesh = mesh.

originSkinnedMesh.parent.remove(originSkinnedMesh)
originSkinnedMesh.parent.add(skinnedmesh)
var newBones =
var bones = skinnedmesh.skeleton.bones
bones.forEach((child) =>
{
if (boneMap[child.name])
{
newBones.push(boneMap[child.name]
}
})
skinnedmesh.skeleton.bones = newBones;
skinnedmesh.skeleton.udpate();
scene.remove(gltf.scene);

1 Like