Search code examples
three.jsoutlinepost-processing

Best method to get Outline effect with animated skinned mesh


What is the best method to get the outline effect with animated skinned mesh?

ThreeJS Outline issue

An example with the model paused at a specific pose: https://jsfiddle.net/Eketol/uev9o0qp/

composer = new THREE.EffectComposer( renderer );
renderPass = new THREE.RenderPass(scene, camera);
renderPass.setSize(window.innerWidth, window.innerHeight);
composer.addPass(renderPass);

outlinePass = new THREE.OutlinePass( new THREE.Vector2( this.viewWidth, this.viewHeight ), scene, camera );
outlinePass.visibleEdgeColor.set( 0xff0000 );
outlinePass.hiddenEdgeColor.set( 0xffff00 );
outlinePass.edgeGlow = 0;
outlinePass.edgeThickness = 0.3; // Default is 1.
outlinePass.edgeStrength = 3; // Default is 3.
outlinePass.setSize(window.innerWidth, window.innerHeight);
composer.addPass(outlinePass);

Another example with animated model: https://jsfiddle.net/Eketol/4xcd365w/

As far as I understand, this is due to the transformations being done in the graphics card, so the code doesn't have a reference of the vertex positions. This issue also affects to the raycaster.

I have read multiple attempts and experiments. Some of them use a glow material, others use two or even three mesh instances with multiple render passes to get the outline done (eg: http://jsfiddle.net/Nv7Up/).

Cons using glow material:

  • The outline thickness will change when the camera distance changes.
  • The outline may not be fully visible if there is another object in front of the selected one.
  • Objects with multiple meshes may look a bit strange (although I could live with it).

Cons using multiple meshes:

  • Maybe ok for simple objects with low polygons, but a hell for custom objects with multiple meshes? Eg: an army of soldiers with random accessories like swords, shields, etc. Not sure how complex would be or what performance cost it would have to clone every skinned object with their custom properties.
  • Instead of using multiple meshes, wouldn't be easier using the original mesh and render it in a secondary scene to get the mask or outline?

Questions:

  1. Is it possible to get the current ThreeJS Outline effect working properly with animated SkinnedMesh?
  2. If the transformed vertex info is on the graphics card, is it possible for the outline shader to get either the vertex info or the rendered image directly from it?
  3. If the above is not possible, is there a method to apply the SkinnedMesh transformations to the vertices so the shader has the correct pose info?

Solution

  • Is it possible to get the current ThreeJS Outline effect working properly with animated SkinnedMesh?

    Yes, however an enhancement of an internal vertex shader is necessary. I've added the respective shader chunks in this updated fiddle (morphtarget_pars_vertex, skinbase_vertex, skinning_pars_vertex, begin_vertex, morphtarget_vertex, skinning_vertex, project_vertex).

    https://jsfiddle.net/35vrtm42/

    But notice that the horse animation is based on morph targets.

    With this enhancement, you only have to tell the OutlinePass to enable the respective animation type. For the fiddle, it was necessary to do this.

    outlinePass.depthMaterial.morphTargets = true;
    outlinePass.prepareMaskMaterial.morphTargets = true;
    

    If your model uses skeletal animation, just replace the morphTargets property with skinning.

    three.js R112