I am trying to get a single SkinnedMesh instance to use in my engine. It doesn’t work with hierarchies, only individual meshes. Here’s the process:
- I have animated model in blender
- I export it using GLTF blender exporter (version from yesterday)
- I load the model in my engine using GLTF loader (version from three.js/dev branch from today)
here’s the model in blender:
here it is in @donmccurdy 's viewer after export:
all looks good!
here’s what it looks like in game (same Idle animation):
here’s the hierarchy in gltf file:
"meshes" : [
{
"name" : "ArmBracelets_high.000",
"primitives" : [
{
"attributes" : {
"JOINTS_0" : 4,
"NORMAL" : 2,
"POSITION" : 1,
"TEXCOORD_0" : 3,
"WEIGHTS_0" : 5
},
"indices" : 0,
"material" : 0
}
]
}
],
"nodes" : [
{
"mesh" : 0,
"name" : "ArmBracelets_high.019",
"scale" : [
1,
1,
1
],
"skin" : 3
},
{
"children" : [
0,
2
],
"name" : "rig.001"
},
{
"children" : [
3,
15,
19
],
"name" : "rig.001_ORG-hips",
"rotation" : [
-0.0010863970965147018,
0.1296624392271042,
-0.005506177898496389,
0.9915423393249512
],
"translation" : [
-0.006763267330825329,
0.9520733952522278,
0.010915498249232769
]
},
....
the rest is not so important i think.
Here’s what I do with the model:
const loader = new GLTFLoader();
loader.load(path, function (gltf) {
const scene = gltf.scene;
/**
* {Array.<THREE.Object3D>}
*/
const children = scene.children;
const foundMesh = findFirstMesh(scene);
const geometry = foundMesh.geometry;
const material = foundMesh.material;
if (gltf.animations !== undefined) {
geometry.animations = gltf.animations;
}
//magic happens here
const result = makeSkinnedMesh(geometry, material, foundMesh.skeleton, foundMesh.bindMatrix);
callback(result);
....
/**
* FIXME
* This is a workaround to a bug in THREE.js
* Skinned mesh cloning doesn't work on meshes loaded via GLTF loader,
* @see https://github.com/mrdoob/three.js/issues/14439
* @see https://github.com/mrdoob/three.js/pull/14494
*
* @param {THREE.BufferGeometry} geometry
* @param {THREE.Material} material
* @param {THREE.Skeleton} originalSkeleton
* @returns {THREE.SkinnedMesh}
*/
function makeSkinnedMesh(geometry, material, originalSkeleton) {
const result = ThreeFactory.createSkinnedMesh(geometry, material);
const originalBones = originalSkeleton.bones;
const numBones = originalBones.length;
//patching up missing bones and invalid skeleton
const bones = cloneBones(originalBones, numBones);
//find root bones
for (let i = 0; i < numBones; i++) {
const bone = bones[i];
if (bone.parent === null) {
//add bone to the mesh
result.add(bone);
}
}
//clone bone inverse matrices of the original skeleton
const boneInverses = originalSkeleton.boneInverses.map(function (mat) {
return mat.clone();
});
const skeleton = new Skeleton(bones, boneInverses);
result.bind(skeleton);
return result;
}
Needless to say… I am a disappoint. I’ve been trying to wrap my head around this but, alas, to no avail so far. I was hoping a fresh pair or eyes might spot some mistakes or that some suggestions may be offered.
I should note that I have very limited ability to author the original model. I have only most basic knowledge of blender and any large changes are beyond my ability. So i’m looking for a way to solve this with extra code around the loader.