<p>Just in case anyone elso also needs to detect edges: 
<a href="http://strattonbrazil.blogspot.de/2011/09/single-pass-wireframe-rendering_10.html" rel="nofollow">Here</a> is a nice article how to display a wireframe and <a href="http://strattonbrazil.blogspot.de/2011/09/single-pass-wireframe-rendering_11.html" rel="nofollow">this</a> article explains how to show only the edges.</p>

CC BY-SA 3.0
2016-08-08T21:12:17.303Z
2016-08-08T21:12:17.303Z
enne87
<p>Generally edge detection boils down to detect areas of the image with high gradient value. </p>

<p>In our case we can crudely see the gradient as the derivative of the image function, therefore the magnitude of the gradient gives you an information on <em>how much</em> your image changes locally (in regards of neighbouring pixels/texels).<br/> Now, an edge is as you say an indication of discontinuity, so now that we defined the gradient is clear that this info is all we need. Once we find the gradient of an image, it's just a matter of applying a threshold to it to obtain a binary value edge/non-edge. </p>

<p>How do you find this gradient is really what you are asking and I am yet to answer :) </p>

<p>Lots of ways! Here a couple :) </p>

<h1>Built in shader functions</h1>

<p>Both hlsl and glsl offer derivative functions. In GLSL you have <a href="https://www.opengl.org/sdk/docs/man/html/dFdx.xhtml" rel="noreferrer">dFdx and dFdy</a> that give you respectively gradient information in x and y direction. Typically these functions are evaluated in a block of 2x2 fragments.<br>
Unless you are interested in a single direction, a good way to have a compact result that indicates how strong is the gradient in the region is <a href="https://www.opengl.org/sdk/docs/man/html/fwidth.xhtml" rel="noreferrer">fwidth</a> that gives you nothing else but the sum of the absolute value of dFdy and dFdy. <br>You are likely to be interested in an edge on the overall image rather than on a specific channel, so you might want to transform your image function to luma. With this in mind,when it comes to edge detection your shader could include something to the like of:</p>

<pre><code>  float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
  float gradient = fwidth(luminance );
  float isEdge = gradient &gt; threshold;
</code></pre>

<p>With an high threshold you will find coarser edges and you might miss some, conversely, with a low threshold you might detect false edges. You have to experiment to find the threshold that better suits your needs. </p>

<p><em>The reason why these functions work is worth mentioning but I don't have time for it now, I am likely to update this answer later on :)</em></p>

<h1>Screen space post-process</h1>

<p>You could go fancier than this, now the field of Edge detection in image processing is immense. I could cite you tens of good ways to detect edge detection according to your needs, but let's keep it simple for now, if you are interested I can cite you more options!</p>

<p>So the idea would be similar to the one above, with the difference that you could look at a wider neighbourhood and use a set of weights on sorrounding samples if you want. Typically, you run a convolution over your image with a kernel that gives you as a result a good gradient info. <br> A very common choice is the Sobel kernel</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://i.sstatic.net/kXrkd.png" rel="noreferrer"><img src="https://i.sstatic.net/kXrkd.png" alt="enter image description here"></a></p>

<p>Which respectively give you gradients in x and y directions: </p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://i.sstatic.net/gCQgw.png" rel="noreferrer"><img src="https://i.sstatic.net/gCQgw.png" alt="From an old pdf I wrote a long time ago."></a></p>

<p>You can get the single value out of the gradient as $ GradientMagnitude = \sqrt{ (Gradient_x) ^ 2 + (Gradient_y) ^ 2 } $ </p>

<p>Then you can threshold as the same way I mentioned above.</p>

<p>This kernel as you can see give more weight to the central pixel, so effectively is computing the gradient + a bit of smoothing which traditionally helps (often the image is gaussian blurred to eliminate small edges). </p>

<p>The above works quite well, but if you don't like the smoothing you can use the Prewitt kernels: </p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://i.sstatic.net/tQ5WJ.png" rel="noreferrer"><img src="https://i.sstatic.net/tQ5WJ.png" alt="enter image description here"></a></p>

<p>(Note I am in a rush, will write proper formatted text instead of images soon! )</p>

<p>Really there are plenty more kernels and techniques to find edge detection in an image process-y way rather than real time graphics, so I have excluded more convoluted (pun not intended) methods as probably you'd be just fine with dFdx/y functions. </p>

CC BY-SA 3.0
2016-05-18T07:31:15.297Z
Very nice explanation cifz, but what if no gradient is visible in a certain situation? For example, there is no light source at the back of the cube and therefore, no gradient is visible. Then this image based edge detection process you describe wouldn't work, am I right?
enne87
CC BY-SA 3.0
2016-05-19T07:24:06.327Z
If you use  a deferred renderer you can do the same but on the normal buffer or again, if you have a prepass you could apply the algorithm to the depth. 
Still you are right, a screen space approach might be not ideal in all cases :) What solution is viable depends a lot on what is your budget for this effect, how complex are your scene.
cifz
CC BY-SA 3.0
2016-05-19T07:40:19.280Z
Potentially if this is really central for your game, a very easy, but potentially taxing, would be computing a gradient on your neighboring normals for each vertex (offline at load time) and pass this factor as additional vertex attribute.
cifz
CC BY-SA 3.0
2016-05-19T09:01:21.427Z
Thangs again cifz for your help.
Well, what I want to achieve is to develop a CAD/CAM solution that looks similar to this: https://www.youtube.com/watch?v=-qTJZtYUDB4
And I really would like to know how they managed it to render all the black edges, creases and ridges.
cifz, do you think as a graphics programming specialis that they achieved this look by using one of your screen space approaches? Or maybe by computing a gradient on neighboring normals? I really want to know how this can be done. Thanks again!
enne87
CC BY-SA 3.0
2016-05-19T09:48:16.243Z
As a premise, I have didn't look that closely to the video as I am at work and super busy :) But judging from the cylindrical green shape at the beginning of the video, they are not using a screen space approach on the final image, as you don't see edges highlighted between that green shape and the white background. Not sure if that is a problem for you, as a first try I'd try a screen space edge detection combining information from depth and normals that should be quite fast to prototype, and if it is failing you go for the offline version or keep experimenting in SS :)
cifz
CC BY-SA 3.0
2016-05-19T09:59:06.440Z
Also, update your question to a reference image of what you are looking for :) Maybe it will attract someone with a precise answer. i'll try and think about it and have a better look at the video if I ever stop being so busy :(
cifz
CC BY-SA 3.0
2016-05-19T15:16:49.877Z
Thank's very much cifz for your hints. The thing is that I'm a total noob regarding OpenG, GLSL and Computer Graphics in general and don't know how to start. I know you haven't that much time but I would be very thankful if you could help me starting programming the shaders. Of course I would gladly pay you for your efforts.
enne87
CC BY-SA 3.0
2016-05-20T13:41:32.590Z
Don't need to pay anyone, just start reading few tutorials online, buy some books and study hard :) It will be very rewarding at the end!
cifz
CC BY-SA 3.0
2016-05-16T21:02:48.873Z
2016-05-16T21:49:48.597Z
2016-05-16T21:49:48.597Z
cifz
<p>I'd like to load arbitrary meshes and draw thick black lines along the edges to get a toon-shading like look.
I managed to draw a black silhouette around the objects by using the stencil buffer. You can see the result here:</p>

<p><a href="https://i.sstatic.net/rPEIz.jpg" rel="noreferrer"><img src="https://i.sstatic.net/rPEIz.jpg" alt="enter image description here"></a></p>

<p>But what's missing are the black lines in the object itself. I thought about checking normal discontinuities: Checking if a neighbouring pixel has a different normal vector than the current one. If yes, an edge has been found. Unfortunately, I've no idea how I could implement this approach, neither in OpenGL nor in GLSL vertex/fragment shader.</p>

<p>I'd be very happy for some help regarding this approach or any other regarding edge detection. </p>

<p>Edit: I do not use any textures for my meshes.</p>

<p>Too be more precise, I would like to create a CAD/CAM solution that looks as much as possible like this (taken from Top Solid <a href="https://www.youtube.com/watch?v=-qTJZtYUDB4" rel="noreferrer">https://www.youtube.com/watch?v=-qTJZtYUDB4</a>):</p>

<p><a href="https://i.sstatic.net/uIZW7.jpg" rel="noreferrer"><img src="https://i.sstatic.net/uIZW7.jpg" alt="enter image description here"></a> </p>

CC BY-SA 3.0
2016-05-17T19:07:58.727Z
I believe you need to define the "edge" more in detail. How does it differ from a simple wireframe? In cifz answer there is a good description of screen space post-process, but from your question it is difficult to determine if it is applicable.
Andreas
CC BY-SA 3.0
2016-05-18T07:27:05.180Z
Well, with edge I mean the "creases" and "ridges" that form the solids. A wireframe would display all triangle faces, which is not what I want.
enne87
CC BY-SA 3.0
2016-05-18T10:44:20.217Z
Ok, exactly what I asked for :-) I would generate a wireframe from those creases and ridges. The tricky part is still to determine what a crease/ridge is. Do you have any idea of how to do that?
Andreas
CC BY-SA 3.0
2016-05-20T14:51:40.600Z
The cad programs do not do this with a shader mostly. Instead they know the hard edges from the model and draw a line on top of the mesh form that info.
joojaa
CC BY-SA 3.0
2017-07-25T20:35:13.490Z
joojaa do you have any more information on this technique? What is done in case of double curved free form surfaces? I'm also not sure what happens when you have a cone or a cylinder that is being cut/trimmed by something free form. https://stackoverflow.com/questions/43795262/silhouette-rendering-with-webgl-opengl
Dusan Bosnjak 'pailhead'
<opengl><edge-detection>
OpenGL - Detection of edges
enne87
# OpenGL - Detection of edges

(Asked by: username_0 on 2016-05-16)

I'd like to load arbitrary meshes and draw thick black lines along the edges to get a toon-shading like look.
I managed to draw a black silhouette around the objects by using the stencil buffer. You can see the result here:

[![enter image description here](https://i.sstatic.net/rPEIz.jpg)](https://i.sstatic.net/rPEIz.jpg)

But what's missing are the black lines in the object itself. I thought about checking normal discontinuities: Checking if a neighbouring pixel has a different normal vector than the current one. If yes, an edge has been found. Unfortunately, I've no idea how I could implement this approach, neither in OpenGL nor in GLSL vertex/fragment shader.

I'd be very happy for some help regarding this approach or any other regarding edge detection.

Edit: I do not use any textures for my meshes.

Too be more precise, I would like to create a CAD/CAM solution that looks as much as possible like this (taken from Top Solid <https://www.youtube.com/watch?v=-qTJZtYUDB4>):

[![enter image description here](https://i.sstatic.net/uIZW7.jpg)](https://i.sstatic.net/uIZW7.jpg)

**Tags:** opengl, edge-detection

> **Comments:**
> **username_1**: I believe you need to define the "edge" more in detail. How does it differ from a simple wireframe? In username_4 answer there is a good description of screen space post-process, but from your question it is difficult to determine if it is applicable.  
> **username_0**: Well, with edge I mean the "creases" and "ridges" that form the solids. A wireframe would display all triangle faces, which is not what I want.  
> **username_1**: Ok, exactly what I asked for :-) I would generate a wireframe from those creases and ridges. The tricky part is still to determine what a crease/ridge is. Do you have any idea of how to do that?  
> **username_2**: The cad programs do not do this with a shader mostly. Instead they know the hard edges from the model and draw a line on top of the mesh form that info.  
> **username_3**: username_2 do you have any more information on this technique? What is done in case of double curved free form surfaces? I'm also not sure what happens when you have a cone or a cylinder that is being cut/trimmed by something free form. https://stackoverflow.com/questions/43795262/silhouette-rendering-with-webgl-opengl  

---

## 2 answers

### Answer by username_4 on 2016-05-16. Score: 19 | Accepted answer

Generally edge detection boils down to detect areas of the image with high gradient value.

In our case we can crudely see the gradient as the derivative of the image function, therefore the magnitude of the gradient gives you an information on *how much* your image changes locally (in regards of neighbouring pixels/texels).  
 Now, an edge is as you say an indication of discontinuity, so now that we defined the gradient is clear that this info is all we need. Once we find the gradient of an image, it's just a matter of applying a threshold to it to obtain a binary value edge/non-edge.

How do you find this gradient is really what you are asking and I am yet to answer :)

Lots of ways! Here a couple :)

# Built in shader functions

Both hlsl and glsl offer derivative functions. In GLSL you have [dFdx and dFdy](https://www.opengl.org/sdk/docs/man/html/dFdx.xhtml) that give you respectively gradient information in x and y direction. Typically these functions are evaluated in a block of 2x2 fragments.  
Unless you are interested in a single direction, a good way to have a compact result that indicates how strong is the gradient in the region is [fwidth](https://www.opengl.org/sdk/docs/man/html/fwidth.xhtml) that gives you nothing else but the sum of the absolute value of dFdy and dFdy.   
You are likely to be interested in an edge on the overall image rather than on a specific channel, so you might want to transform your image function to luma. With this in mind,when it comes to edge detection your shader could include something to the like of:

```
  float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
  float gradient = fwidth(luminance );
  float isEdge = gradient > threshold;

```

With an high threshold you will find coarser edges and you might miss some, conversely, with a low threshold you might detect false edges. You have to experiment to find the threshold that better suits your needs.

*The reason why these functions work is worth mentioning but I don't have time for it now, I am likely to update this answer later on :)*

# Screen space post-process

You could go fancier than this, now the field of Edge detection in image processing is immense. I could cite you tens of good ways to detect edge detection according to your needs, but let's keep it simple for now, if you are interested I can cite you more options!

So the idea would be similar to the one above, with the difference that you could look at a wider neighbourhood and use a set of weights on sorrounding samples if you want. Typically, you run a convolution over your image with a kernel that gives you as a result a good gradient info.   
 A very common choice is the Sobel kernel

[![enter image description here](https://i.sstatic.net/kXrkd.png)](https://i.sstatic.net/kXrkd.png)

Which respectively give you gradients in x and y directions:

[![From an old pdf I wrote a long time ago.](https://i.sstatic.net/gCQgw.png)](https://i.sstatic.net/gCQgw.png)

You can get the single value out of the gradient as $ GradientMagnitude = \sqrt{ (Gradient\_x) ^ 2 + (Gradient\_y) ^ 2 } $

Then you can threshold as the same way I mentioned above.

This kernel as you can see give more weight to the central pixel, so effectively is computing the gradient + a bit of smoothing which traditionally helps (often the image is gaussian blurred to eliminate small edges).

The above works quite well, but if you don't like the smoothing you can use the Prewitt kernels:

[![enter image description here](https://i.sstatic.net/tQ5WJ.png)](https://i.sstatic.net/tQ5WJ.png)

(Note I am in a rush, will write proper formatted text instead of images soon! )

Really there are plenty more kernels and techniques to find edge detection in an image process-y way rather than real time graphics, so I have excluded more convoluted (pun not intended) methods as probably you'd be just fine with dFdx/y functions.

> **Comments:**
> **username_0**: Very nice explanation username_4, but what if no gradient is visible in a certain situation? For example, there is no light source at the back of the cube and therefore, no gradient is visible. Then this image based edge detection process you describe wouldn't work, am I right?  
> **username_4**: If you use  a deferred renderer you can do the same but on the normal buffer or again, if you have a prepass you could apply the algorithm to the depth.  Still you are right, a screen space approach might be not ideal in all cases :) What solution is viable depends a lot on what is your budget for this effect, how complex are your scene.  
> **username_4**: Potentially if this is really central for your game, a very easy, but potentially taxing, would be computing a gradient on your neighboring normals for each vertex (offline at load time) and pass this factor as additional vertex attribute.  
> **username_0**: Thangs again username_4 for your help. Well, what I want to achieve is to develop a CAD/CAM solution that looks similar to this: https://www.youtube.com/watch?v=-qTJZtYUDB4 And I really would like to know how they managed it to render all the black edges, creases and ridges. username_4, do you think as a graphics programming specialis that they achieved this look by using one of your screen space approaches? Or maybe by computing a gradient on neighboring normals? I really want to know how this can be done. Thanks again!  
> **username_4**: As a premise, I have didn't look that closely to the video as I am at work and super busy :) But judging from the cylindrical green shape at the beginning of the video, they are not using a screen space approach on the final image, as you don't see edges highlighted between that green shape and the white background. Not sure if that is a problem for you, as a first try I'd try a screen space edge detection combining information from depth and normals that should be quite fast to prototype, and if it is failing you go for the offline version or keep experimenting in SS :)  
> **username_4**: Also, update your question to a reference image of what you are looking for :) Maybe it will attract someone with a precise answer. i'll try and think about it and have a better look at the video if I ever stop being so busy :(  
> **username_0**: Thank's very much username_4 for your hints. The thing is that I'm a total noob regarding OpenG, GLSL and Computer Graphics in general and don't know how to start. I know you haven't that much time but I would be very thankful if you could help me starting programming the shaders. Of course I would gladly pay you for your efforts.  
> **username_4**: Don't need to pay anyone, just start reading few tutorials online, buy some books and study hard :) It will be very rewarding at the end!  

---

### Answer by username_0 on 2016-08-08. Score: 4

Just in case anyone elso also needs to detect edges:
[Here](http://strattonbrazil.blogspot.de/2011/09/single-pass-wireframe-rendering_10.html) is a nice article how to display a wireframe and [this](http://strattonbrazil.blogspot.de/2011/09/single-pass-wireframe-rendering_11.html) article explains how to show only the edges.


---

