Outlines around objects (cartoonish effect)

Hi all I am looking for a shader or some other way of drawing black outlines around every object in my scene including animated models like this:

its subtle but you can still see it if you look closely
thank you all for pointing me to any resources

Maybe render scene and soldier without edge, then use renderer.clearDepth();, and render only soldier edge posteffect (black lines). If edge effect without posteffect then use renderOrder=1; for soldier edge:

@Bravest I am working on something similar in terms of the effect, this will help you: LDraw-like edges

1 Like

Worth to see: How to render full outlines as a post process - tutorial

1 Like

There’s also this component from Drei.

1 Like

this one GitHub - pmndrs/drei: 🥉 useful helpers for react-three-fiber (link was broken)

in react this is trivial now:

<mesh geomery={foo} material={bar}>
  <Outlines />
</mesh>

if you want it in vanilla, the code is here https://raw.githubusercontent.com/pmndrs/drei/master/src/core/Outlines.tsx and imo that’s your best chance. ldraw-like edges from above are very complex to implement and need a postpro step geared towards it. and shaded outlines (like drei’s) also had their challanges, like enabling them for instanced and skinned objects wasn’t easy.

3 Likes

Sadly I’m not using react

that’s why i linked the source code and the THREE.ShaderMaterial.

const OutlinesMaterial = /* @__PURE__ */ shaderMaterial(
  {
    screenspace: false,
    color: /* @__PURE__ */ new THREE.Color('black'),
    opacity: 1,
    thickness: 0.05,
    size: /* @__PURE__ */ new THREE.Vector2(),
  },
  `#include <common>
   #include <morphtarget_pars_vertex>
   #include <skinning_pars_vertex>
   uniform float thickness;
   uniform float screenspace;
   uniform vec2 size;
   void main() {
     #if defined (USE_SKINNING)
	     #include <beginnormal_vertex>
       #include <morphnormal_vertex>
       #include <skinbase_vertex>
       #include <skinnormal_vertex>
       #include <defaultnormal_vertex>
     #endif
     #include <begin_vertex>
	   #include <morphtarget_vertex>
	   #include <skinning_vertex>
     #include <project_vertex>
     vec4 tNormal = vec4(normal, 0.0);
     vec4 tPosition = vec4(transformed, 1.0);
     #ifdef USE_INSTANCING
       tNormal = instanceMatrix * tNormal;
       tPosition = instanceMatrix * tPosition;
     #endif
     if (screenspace == 0.0) {
       vec3 newPosition = tPosition.xyz + tNormal.xyz * thickness;
       gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); 
     } else {
       vec4 clipPosition = projectionMatrix * modelViewMatrix * tPosition;
       vec4 clipNormal = projectionMatrix * modelViewMatrix * tNormal;
       vec2 offset = normalize(clipNormal.xy) * thickness / size * clipPosition.w * 2.0;
       clipPosition.xy += offset;
       gl_Position = clipPosition;
     }
   }`,
  `uniform vec3 color;
   uniform float opacity;
   void main(){
     gl_FragColor = vec4(color, opacity);
     #include <tonemapping_fragment>
     #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
   }`
)
1 Like