I have a Skinned Mesh of a person and I am wanting to add and exchange hair, clothes, ect… on the person. I can add the hair and it is positioned properly. When I export it as a gltf, the hair is loosely attached and floats around the head as the person is animated.
I’m attaching it thus:
avatar.traverse(function (element) {
if (element.name == "Avatar_base"){
hair.traverse(function (bits) { // Blender exports gltf as group
if(bits.name == "Base_Hair"){ // Find the mesh we want
SceneUtils.attach( bits, avatar, element); // attach it to the skinned mesh
}
});
scene.needsUpdate = true;
}
});
Do I need to bind the hair and clothing to the skeleton or add it to a vertex group or some other mechanism to get this to stay firmly in place?
Thanks…
Maybe this thread could help you?
That is a very interesting and ingenious solution. Does the mesh take place in a group? It seems as if you are replacing the bone with the mesh…
1 Like
Sorry, I logged in with a different GMail account…
I have given this some thought. The problem I have is that using the above method I would have to create a bone for everything that I want to attach to the model. That’s limiting and not very practical for my application. Say I wanted to layer different sets of clothes there is a finite number based upon how many bones I create using the suggested method.
So far I can attach and add things to the model with the same net effect. They appear fine but when I export the gltf they are loosely attached and don’t move with the animation. What I cannot do and what I suspect I need to be capable of, is binding the mesh to the skeleton. I notice that other meshes attached have a bindMatrix and bindMatrixInverse object. How can I bind my mesh to the skeleton (or a bone) in a SkinnedMesh so that it becomes part of the model… not just an attachment?
When I use bind I get a “bind is not a function error.”
Perhaps adding the things I have tried will help.
avatar.traverse(function (element) {
if (element.name == "Avatar_base"){Avatar_base = element; console.log(Avatar_base);}
if (element.name == "Base_Body"){ // Head is a bone
hair.traverse(function (bits) {
if(bits.name == "Base_Hair"){
SceneUtils.attach( bits, avatar, Avatar_base); // attach to head works
//element.skeleton.bones[37].add(bits);
//element.add(bits); // add to head works
//element.skeleton.bones[37].add(bits);
element.updateMatrixWorld(true); //No effect
bits.updateMatrixWorld(true); //No effect
// bits.bind(element.skeleton); //No effect bits.bind not a function
}
});
//SceneUtils.attach( hair, avatar, element);
scene.needsUpdate = true;
}
});
I can see no apparent difference between using add or attach functions… can somebody explain what the difference is? Does anyone know how to bind a mesh to an existing skeleton of an existing SkinnedMesh? or… a way to add the transforms to the newly attached/added mesh?
This is what I have so far… as you can see I am trying to be sneaky and copy the bindMatrix from an already existing attached object. After examining a few I realized they are the same… doesn’t help fix my problem.
function attachHair(){
loader.load(’/public/makeavatar/data/hair/Base_Hair_05.glb’, function (hair_gltf) {
var hair = hair_gltf.scene;
hair.name = “Avatar_Hair”;
hair.scale.set(2, 2, 2);
hair.position.set(0, -2.5, 0);
let Avatar_base;
let bone;
let $bindMatrix = new Matrix4();
let $bindMatrixInverse = new Matrix4();
let $skeleton = new Skeleton();
avatar.traverse(function (element) {
if (element.name == “Avatar_base”){Avatar_base = element;}
if (element.name == “Base_Eyes”){console.log(‘eyes’);
$bindMatrix = element.bindMatrix;
$bindMatrixInverse = element.bindMatrixInverse;
$skeleton = element.skeleton;
}
if (element.name == “Base_Body”){ // Head is a bone
hair.traverse(function (bits) {
if(bits.name == “Base_Hair”){
//SceneUtils.attach( bits, avatar, Avatar_base); // attach to head works
bits.scale.set(2, 2, 2);
bits.position.set(0, -2.5, 0);
Avatar_base.add(bits);
//element.updateMatrixWorld(true);
bits.skeleton = $skeleton;
//bits.bind($skeleton, $bindMatrix);
bits.bindMatrix = $bindMatrix;
bits.bindMatrixInverse = $bindMatrixInverse;
bits.bindMode = ‘attached’;
bits.type = ‘SkinnedMesh’;
bits.visible = true;
//bits.updateMatrixWorld(true);
}
});
//SceneUtils.attach( hair, avatar, element);
scene.needsUpdate = true;
}
});
Pardon a late reply. Wouldn’t it be enough to place a Three.Group
in place of the bone - and the add / remove stuff from that group? (Group will inherit the transforms from the bone, and children within the group will then all inherit transforms from the group.)
I can’t exactly recall why replacing bones (and replacing submeshes didn’t) worked, but it’s probably fair to assume it’s just how the skinned meshes are parsed and connected to the armature.
I did play with adding the mesh to the SkinnedMesh in a group together but perhaps your idea will work. I’ll reply back once I have had some time to experiment with it. Thank you…
Well, it works splendidly in three.js… however the 3D World application Vircadia crashes on the gltf export… humph! I’m going to try to export the data from the part attached via blender and see if I can’t use it to manipulate the structure… not sure why this is so difficult.