Three.js: GLTF anim and morph playback issue when using three.js with more than one mixer

Created on 30 Jan 2019  Â·  6Comments  Â·  Source: mrdoob/three.js

Description of the problem

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

Also posted to SO

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).

Three.js version
  • [ ] Dev
  • [ ] r100
  • [x] r98
Browser
  • [x] All of them
  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
OS
  • [x] All of them
  • [ ] Windows
  • [ ] macOS
  • [ ] Linux
  • [ ] Android
  • [ ] iOS
Hardware Requirements (graphics card, VR Device, ...)
Bug Duplicate

Most helpful comment

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.

All 6 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yqrashawn picture yqrashawn  Â·  3Comments

boyravikumar picture boyravikumar  Â·  3Comments

konijn picture konijn  Â·  3Comments

akshaysrin picture akshaysrin  Â·  3Comments

jack-jun picture jack-jun  Â·  3Comments