I have a single gltf file, exported from Blender with 6 anims and 20 morph targets. When that's the only skinned gltf object in the scene, everything plays nicely - I can switch between bone anims (run, walk, idle, etc), and get all morph anims (for facial expressions) cycling on a timer, or triggered by events.
The problem is when I introduce a second skinned (and/or morphed) object, such as an NPC. At that point lots of weirdness starts to happen.
I have created a demo illustrating one of the main issues here
Please note, the morphs on the player (the caped one that looks a bit like #45 - the commader in chief not the post) cycle on ~10sec intervals. Within that time you should start to see the magical bone-warping disappearing/reappearing act played by the NPC (the guy with an untucked shirt).
Thanks for filing the issue! One issue I notice up front is that at least two of the files (alvin.gltf, drumpfwix.gltf) use more than 4 joint influences. You can fix that when exporting from Blender by applying the Limit Total operation, or I think newer versions of the glTF exporter will avoid writing more than 4 unless a specific option is selected. Typically more influences are not needed, and the strongest 4 are enough.
It may not just be that, but it seems like a start.
Thanks Don, I'll look into it. I also just updated the demo file to see things better (removed the terrain, adjusted camera). The NPC's bones appear to get inverted along the vertical axis, as well as re-scaled. Will keep trying to isolate the problem.
I've reduced the joint influences to 4, and updated the demo file, but it does not seem to have any effect. What appears to be happening visually is the NPC (alvin.gltf) is taking on the bone orientation and scaling of the player (drumpfwix.gltf), when the player facial morphs become active.
After loading the NPC, your code changes its material here:
const oldMat = child.material;
const newMat = new THREE.MeshLambertMaterial({
color: oldMat.color,
morphTargets: true,
transparent: true,
alphaTest: 0.5,
skinning: true,
map: oldMat.map
});
I don't think you want all of that – the mesh doesn't have morph targets, and isn't transparent. Setting transparency will have intended side effects, and in this case it looks like setting morphTargets:true is having _unintended_ side effects. Removing that, the NPC is no longer affected by the Player's morph targets.
This bug seems only to affect meshes without morph targets rendered with a material where morphTargets=true. Setting morph targets, or even an empty array like .morphTargetInfluences = [], will also fix the issue.
The underlying problem is tracked by https://github.com/mrdoob/three.js/issues/9626, so I'll close this issue.
Excellent. Thank you Don. I now have two instances of Drumpfwix successfully making faces at each other :). I'm not having much luck with an if(child.morphTargetInfluences) check outside the newMat array to catch cases where an NPC loads without morph targets, so I'll just plan to create a dummy shape key in Blender prior to export.
I'm not having much luck with an if(child.morphTargetInfluences)
I think it would be enough to check if the old material has .morphTargets enabled, but creating a dummy shape key should work as well.
Most helpful comment
After loading the NPC, your code changes its material here:
I don't think you want all of that – the mesh doesn't have morph targets, and isn't transparent. Setting transparency will have intended side effects, and in this case it looks like setting
morphTargets:trueis having _unintended_ side effects. Removing that, the NPC is no longer affected by the Player's morph targets.This bug seems only to affect meshes without morph targets rendered with a material where morphTargets=true. Setting morph targets, or even an empty array like
.morphTargetInfluences = [], will also fix the issue.The underlying problem is tracked by https://github.com/mrdoob/three.js/issues/9626, so I'll close this issue.