MorphTargetManager: _syncActiveTargets called multiple time pre frame

Version: 8.32.1

Steps to reproduce:

  1. Open the playground: https://playground.babylonjs.com/#BRK9XW
  2. Wait for model loaded
  3. Open devtools console and watch the “total _syncActiveTargets called” log

Expected:
One goToFrame, or one regular animation frame emits one call to _syncActiveTargets per morphed mesh

Actual:
total _syncActiveTargets called: 14

Background:
Following Number of meshes significantly drop fps - #15 by kzhsw, where a profiler shows _syncActiveTargets costs most the cpu time, and the code shows every morph target update calls _syncActiveTargets to update all the morph target manager.

Call stack:
MorphTargetManager._syncActiveTargets
anonymous function in MorphTargetManager.addTarget
MorphTarget.onInfluenceChanged.notifyObservers
set MorphTarget.influence
RuntimeAnimation._setValue

For certain reasons, the base mesh also includes morph targets. There are therefore 8*2=16 targets in the scene. In frame 62, two targets have zero influence, leaving 14 non-zero targets, which is the number shown in the console.

Note that this is an asset-related issue, not a Babylon issue. The 3js glTF viewer also displays 16 targets:

Well, the thing is, _syncActiveTargets updates the whole MorphTargetManager, not a single target, so it should be called per animation frame per MorphTargetManager, instead of per MorphTarget, which makes a lot of redundant calls and increases cpu time.

Sorry, I didn’t understand it was the problem.

This PR should fix it:

After the PR is merged, this PG will output a count of 2:

2 Likes

Yeah, it works. Thank you for the quick fix.

But some CI failed to run now