Dev log #1: Morph targets

This is the first post of a series about what I’m working on for Babylon.js.

Morph targets were on my todo list since ages (since Babylon.js 1.4 if I remember correctly). I decided recently to do it because I wanted to be sure we can cover all aspects of gltf 2.0

Morph targets are used to deform meshes. A morph target can be built from a mesh with the EXACT same amount of vertices as the original mesh.

Morph targets are used by the GPU to create the final geometry by applying the following formula:

final mesh = original mesh + sum((morph targets – original mesh) * morph targets influences)

__ 

You can then move from this:

Morph Target Before

to this:

Morph Target After

You can find a live example right here: https://www.babylonjs-playground.com/#HPV2TZ#4

 

Thanks to our smart shader system, the implementation was not really hard. I first introduced two shader includes:

https://github.com/BabylonJS/Babylon.js/blob/master/src/Shaders/ShadersInclude/morphTargetsVertexDeclaration.fx

https://github.com/BabylonJS/Babylon.js/blob/master/src/Shaders/ShadersInclude/morphTargetsVertex.fx

The integration in the Standard and PRB materials was then straightforward:

https://github.com/BabylonJS/Babylon.js/blob/master/src/Shaders/default.vertex.fx#L107

Basically based on number of target, the vertex shader will apply the initial formula:

position = initialPosition + sum((targetPositionX – initialPosition) * influenceX)

The same operation is applied to normal if they are present.

 

On JavaScript (well TypeScript actually) side, I added a new function to add vertex attributes when a mesh is used with a morph target:

https://github.com/BabylonJS/Babylon.js/blob/master/src/Materials/babylon.materialHelper.ts#L245

Ultimately, when you bind morph targets to a mesh, the geometry of the mesh is updated to add a vertex buffer per target:

https://github.com/BabylonJS/Babylon.js/blob/master/src/Mesh/babylon.mesh.ts#L2003

By updating the geometry we ensure that the vertex buffers will be captured within VAO (Vertex array objects) which were introduced recently in Babylon.js.

 

So we have here:

  • A hardware accelerated morphing of geometries
  • Support of VAO
  • Works on WebGL 1 and 2
  • Can be used on mobile devices
  • Can used from 1 to x morph targets (where x is limited by maxVertexAttribs which is usually 16 on recent browsers. So with position, normal and uv, this leaves 13 free attributes so either 13 targets with position only or 6 targets with position and normal)