Messed up animation

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:

  1. I have animated model in blender
  2. I export it using GLTF blender exporter (version from yesterday)
  3. 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! :slight_smile:

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. :frowning: 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.

If you print a graph of the glTF file’s original content (I use the snippet below) what do you get?

function printGraph (node) {

    console.group(' <' + node.type + '> ' + node.name);
    node.children.forEach((child) => this.printGraph(child));
    console.groupEnd();

}

The bones may not be children of the mesh, so I’m wondering if there’s some edge case there, related to throwing out parent nodes. And then I suppose the obvious question, does it work if you disable the magic happens here part? :sweat_smile:

1 Like

Hey Don,

Thank your for your reply, here’s what I get when I dump contents of the “scene” node that’s returned by the GLTFLoader:
image

which looks about right. The problem here is - parent bone is a child of a grouping Object3D, but not of the skinned mesh, so parent bone and the mesh are siblings.

Here’s what the hierarchy looks like on “result” after “magic happens here”:
image

if i remove the “magic happens here” part - my engine just doesn’t work with the model, as it only works with unwrapped meshes. I believe that everything would be okay, as in your gltf viewer - it looks absolutely fine (see screenshot in original post).