Animated Dotted Outline Shader in Unity

Earlier, I wrote a tutorial on how to create a cel shader with an outline effect. For the sake of not repeating that explanation, refer to that tutorial to learn how to draw the basic outline.

You can apply this outline effect to any kind of lighting or other shader properties, since it’s in its own pass.

Here’s the final code for you to reference:

–> Link to final code for Unity Dotted Outline Shader


Dotted Outline

The dotted shader is achieved with two techniques:

  1. Using a distance field to skip pixels when drawing the outline
  2. Scrolling the ‘position’ of each pixel with Time to animate

So, let’s say we’ve already got our shader drawing the outline. We can leave the regular lighting & texture pass alone for this shader. We’re going to focus completely on the fragment shader of the outline pass.

First, let’s learn how to draw the lines.

If you’re unfamiliar with distance fields, the basic premise is that you can determine what to render for a pixel based on its distance from a particular point. In this shader, we discard every other set of X pixels in a radius around a point. If we take away the regular lighting pass, and only draw the outline pass, the curve to the lines becomes more apparent:

lines

Here’s what the fragment shader code to break up the outline looks like:

// _OutlineDot = width of solid portion
// _OutlineDot2 = width of transparent portion
float skip = sin(_OutlineDot*abs(distance(_SourcePos.xy, pos))) + _OutlineDot2;

// clip stops rendering a pixel if 'skip' is negative
clip(skip);

return _OutlineColor;

Let’s break this down.

  • We measure the distance of every pixel from _SourcePos.xy with the call distance(_SourcePos.xy, pos).
  • We then take the sin of the absolute value of that distance, which oscillates between negative and positive values.
  • We use _OutlineDot and _OutlineDot2 (lazy names, I know) to modify the frequency of the negative and positive values.
  • Then, the call to clip(skip) will discard any pixels where the value of skip is negative.
  • Finally, we return the basic, flat _OutlineColor for every pixel that wasn’t discarded.

So that’s how we get the dotted outline! Try doing that before moving on to animation.

Here’s the animation code:

float2 pos = input.pos.xy + _Time * _OutlineSpeed;

This is quite a bit simpler.

  • We get the current position with input.pos.xy (this was passed in from the vertex shader)
  • We multiply the position by _Time and _OutlineSpeed in order to translate the position over time.

Here’s the full fragment shader together:

// if you want to remove the animation, remove "+ _Time * _OutlineSpeed"
float2 pos = input.pos.xy + _Time * _OutlineSpeed;

// _OutlineDot = width of solid portion
// _OutlineDot2 = width of transparent portion
float skip = sin(_OutlineDot*abs(distance(_SourcePos.xy, pos))) + _OutlineDot2;

// stops rendering a pixel if 'skip' is negative
clip(skip);

return _OutlineColor;

 


Extra Reference

 

Tutorial on distance fields in The Book of Shaders.

Ramp shader used for lighting:

ramp

Tuning used in the header gif:

dottedMaterialProperties


Fin

Here’s a link to the final code for the dotted outline shader, including a pass for cel-shaded lighting and a pass for shadows.

I hope y’all found this useful! If y’all have any questions about writing shaders in Unity, I’m happy to share as much as I know. I’m not an expert, but I’m always willing to help other indie devs 🙂

Good luck,

Lindsey Reid @so_good_lin

 

Published by

Linden Reid

Game developer and tutorial writer :D

4 thoughts on “Animated Dotted Outline Shader in Unity”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s