4

Is it possible to have an black outline on my 3d models with three.js?

I would have graphics which looks like Borderlands 2. (toon shading + black outlines)

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
user2018005
  • 61
  • 2
  • 5

3 Answers3

8

I'm sure I came in late. Let's hope this would solve someone's question later.

Here's the deal, you don't need to render everything twice, the overhead actually is not substantial, all you need to do is duplicate the mesh and set the duplicate mesh's material side to "backside". No double passes. You will be rendering two meshes instead, with most of the outline's geometry culled by WebGL's "backface culling".

Here's an example:

var scene = new THREE.Scene();

//Create main object
var mesh_geo = new THREE.BoxGeometry(1, 1, 1);
var mesh_mat = new THREE.MeshBasicMaterial({color : 0xff0000});
var mesh = new THREE.Mesh(mesh_geo, mesh_mat);
scene.add(mesh);

//Create outline object
var outline_geo = new THREE.BoxGeometry(1, 1, 1);
//Notice the second parameter of the material
var outline_mat = new THREE.MeshBasicMaterial({color : 0x00ff00, side: THREE.BackSide});
var outline = new THREE.Mesh(outline_geo, outline_mat);
//Scale the object up to have an outline (as discussed in previous answer)
outline.scale.multiplyScalar(1.5);
scene.add(outline);

For more details on backface culling, check out: http://en.wikipedia.org/wiki/Back-face_culling

The above approach works well if you want to add an outline to objects, without adding a toon shader, and thus losing "realism".

Toon shading by itself supports edge detection. They've developed the 'cel' shader in Borderlands to achieve this effect.

In cel shading devs can either use the object duplication method (done at the [low] pipeline level), or can use image processing filters for edge detection. This is the point at which performance tradeoff is compared between the two techniques.

More info on cel: http://en.wikipedia.org/wiki/Cel_shading

Cheers!

Ali Hammoud
  • 325
  • 2
  • 12
  • I tried this with complex shapes and the second outline mesh conflicts with the main one by sometimes being shown on entire faces over the original. – Blubberguy22 Jun 24 '15 at 12:53
  • 1
    @Blubberguy22 - yeah, that works only for simple, convex shapes. You'd need post-processing for it to be more accurate. It also draws bigger outlines for bigger objects due to scaling, so keep that in mind. – klh Dec 08 '15 at 20:12
  • Thanks so much for this! I was able to create a "solid" color background of this globe component that I'm making and have the edges extend out a bit. As a normal mesh this would hide the land polygons. https://cdf0d25d.spinny-globe.pages.dev/ – phocks Feb 06 '23 at 05:59
0

Yes it is possible but not in a simple out-of-the-box way. For toon shading there are even shaders included in /examples/js/ShaderToon.js

For the outlines I think the most commonly suggested method is to render in two passes. First pass renders the models in black, and slightly larger scale. Second pass is normal scale and with the toon shaders. This way you'll see the larger black models as an outline. It's not perfect but I don't think there's an easy way out. You might have more success searching for "three.js hidden line rendering", as, while different look, somewhat similar method is used to achieve that.

yaku
  • 3,061
  • 2
  • 19
  • 38
  • Thank you, but two renders on each frames will divide fps by 2 ? Maybe less if the first render (for black models) render only the black characters. And objects of the scenery on the second render will hide the black models, no? – user2018005 Jan 28 '13 at 17:54
  • Yes I would think all of those are valid concerns. You don't need any shading, lights, shadows or stuff the first render, so it's definitely cheaper but not free. And scenery would need to be handled somehow, maybe render them on the first pass too or something. I haven't done it so my experience is limited. – yaku Jan 28 '13 at 19:07
  • Please. Is it possible to have any explications on the part which concern outlines in this : [link](http://3-dreams-of-black.googlecode.com/git/tests/shading/toon4.html) ? Thank you – user2018005 Jan 29 '13 at 22:51
0

Its a old question but here is what i did.

I created a Outlined Cel-shader for my CG course. Unfortunately it takes 3 rendering passes. Im currently trying to figure out how to remove one pass.

Here's the idea: 1) Render NormalDepth image to texture.

In vertex shader you do what you normally do, position to screen space and normal to screen space.

In fragment shader you calculate the depth of the pixel and then create the normal color with the depth as the alpha value

float ndcDepth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) / (gl_DepthRange.far - gl_DepthRange.near);
float clipDepth = ndcDepth / gl_FragCoord.w;

2) Render the scene on to a texture with cel-shading. I changed the scene override material.

3)Make quad and render both textures on the quad and have a orto camera look at it. Cel-shaded texture is just renderd on quad but the normaldepth shaded on that you use some edge detection and then with that you know when the pixel needs to be black(edge).

BWA
  • 5,672
  • 7
  • 34
  • 45
Marko Taht
  • 1,448
  • 1
  • 20
  • 40