Merging Multiple Morph Targets in readyPlayerMe avatars

readyPlayerMe avatars come with 63 facial morphTargets. Animating an expression on THREE.js requires tweening many of these simultaneously, e.g. surprise - “jawOpen”, “eyeWideLeft”, “eyeWideRight”, “browOuterUpLeft”…etc. This is cumbersome (especially with multiple avatars) and doesn’t work well as the number of morphTargets increases above 3.

Desired Solution
Is there a way to create new morphTargets by merging those which ship with the avatar? i.e. create a 64th “surprise” morphTarget which equals “0.8 x jawOpen” + “0.5 X eyeWideLeft” + …etc.? Blender has a “New Shape From Mix” function that does exactly this.

Research so far has drawn a blank, and numerous attempts to manually add to morphAttributes have been unsuccessful. Any help would be much appreciated,


Finally figured it out. It’s a manual workaround but it does the job. Here’s the solution if anyone else is facing the same issue:

  1. Create new Float32BufferAttributes for position and normal with one of the existing morphs which make up the desired new expression (e.g. 45 is “jawOpen” in this case"):
    const newMorphTargetPosition = new THREE.Float32BufferAttribute( mesh.geometry.morphAttributes.position[45].array, 3 )
    const newMorphTargetNormal = new THREE.Float32BufferAttribute( mesh.geometry.morphAttributes.position[45].array, 3 )

  2. Add these to the morphAttributes arrays:
    mesh.geometry.morphAttributes.position = [...mesh.geometry.morphAttributes.position, newMorphTargetPosition]
    mesh.geometry.morphAttributes.normal = [...mesh.geometry.morphAttributes.normal, newMorphTargetNormal]

  3. Give it a name and index:
    mesh.morphTargetDictionary['surprise'] = 63

  4. Append a value to morphTargetInfluences:
    mesh.morphTargetInfluences = [...mesh.morphTargetInfluences, 0]

Now you can add other morphs on top by element-wise adding their position and normal arrays to this new morph :slight_smile:

If anyone has a more elegant solution please let me know!