OmarShehata / webgl-outlines

Implementation of a post process outline shader in ThreeJS & PlayCanvas.
MIT License
360 stars 39 forks source link

Support applying outlines to individual objects #3

Open OmarShehata opened 3 years ago

OmarShehata commented 3 years ago

This PR adds support for applying the outline to individual objects. It is not intended to be merged because doing this requires an additional render pass.

outline_selected

To apply the outline on an object, enable it with:

mesh.traverse(node => node.applyOutline = true);

How it works

For reference, here is the original pipeline described here: https://omar-shehata.medium.com/how-to-render-outlines-in-webgl-8253c14724f9

image

To apply outlines selectively, we need to create normal & depth buffers that ONLY include the outlined object(s). However, the original scene buffer still needs to include all the objects. In addition, the final outline must be occluded by objects in front of it, even if they do not have outlines applied.

My initial approach was to make render pass 2 only include the outlined objects, and use the depth & normal buffers from that. This works and does not add any additional render passes, but the final outline can be "seen through" objects in front it, because then the normal buffer that is used to compute the outlines doesn't include any foreground cubes to occlude it.

To fix this, we add an additional render pass to get a depth buffer with just the objects that do NOT have an outline on them. We then use this to apply a manual depth test in the shader:

// If the depth of the current object is greater
// than an object without outlines
// that means further away from the camera, so the outline shouldn't be visible here
if ( depth > nonOutlinesDepth ) {
    outline = 0.0;
}

The new render pipeline is shown below, including snapshots of what each buffer looks like:

rendering_diagram