20
2018
Marching Ants Sprite Outline Shader
Saw interesting question here https://forum.unity.com/threads/animated-outline-effects-using-shader.600028/
and unity sprite outline https://github.com/wlgys8/Sprites-Outline + stackoverflow https://stackoverflow.com/a/16856878/5452781 to the rescue!
(although this is for 2D sprite..)
Results:

TODO
– Test how this would look with screenspace values (to keep same size even if zoomed)
– Maybe could check neighbor pixel to get “flowing direction” for each pixel ?
Modified shader: *note: hard coded values, could put them into properties, and also download the original github project first to test.
| // original source: https://github.com/wlgys8/Sprites-Outline | |
| Shader "Sprites/Outline (Marching Ants)" | |
| { | |
| Properties | |
| { | |
| [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} | |
| _Color ("Tint", Color) = (1,1,1,1) | |
| [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0 | |
| // Add values to determine if outlining is enabled and outline color. | |
| [PerRendererData] _OutlineSize ("Outline", Float) = 0 | |
| [PerRendererData] _OutlineColor("Outline Color", Color) = (1,1,1,1) | |
| } | |
| CGINCLUDE | |
| #include "UnityCG.cginc" | |
| struct appdata_t | |
| { | |
| float4 vertex : POSITION; | |
| float4 color : COLOR; | |
| float2 texcoord : TEXCOORD0; | |
| }; | |
| struct v2f | |
| { | |
| float4 vertex : SV_POSITION; | |
| fixed4 color : COLOR; | |
| float2 texcoord : TEXCOORD0; | |
| }; | |
| fixed4 _Color; | |
| v2f vert_outline(appdata_t IN) | |
| { | |
| v2f OUT; | |
| OUT.vertex = UnityObjectToClipPos(IN.vertex); | |
| OUT.texcoord = IN.texcoord; | |
| OUT.color = IN.color * _Color; | |
| #ifdef PIXELSNAP_ON | |
| OUT.vertex = UnityPixelSnap (OUT.vertex); | |
| #endif | |
| return OUT; | |
| } | |
| sampler2D _MainTex; | |
| sampler2D _AlphaTex; | |
| float4 _MainTex_TexelSize; //magic var | |
| float _OutlineSize; //outline size | |
| fixed4 _OutlineColor; // outlie color | |
| fixed4 SampleSpriteTexture (float2 uv) | |
| { | |
| fixed4 color = tex2D (_MainTex, uv); | |
| return color; | |
| } | |
| ENDCG | |
| SubShader | |
| { | |
| Tags | |
| { | |
| "Queue"="Transparent" | |
| "IgnoreProjector"="True" | |
| "RenderType"="Transparent" | |
| "PreviewType"="Plane" | |
| "CanUseSpriteAtlas"="True" | |
| } | |
| Cull Off | |
| Lighting Off | |
| ZWrite Off | |
| Blend One OneMinusSrcAlpha | |
| //outline down | |
| Pass | |
| { | |
| Offset 1, 1 | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma fragment frag | |
| #pragma multi_compile _ PIXELSNAP_ON | |
| #pragma shader_feature ETC1_EXTERNAL_ALPHA | |
| v2f vert(appdata_t IN) | |
| { | |
| return vert_outline(IN); | |
| } | |
| fixed4 frag(v2f IN) : SV_Target | |
| { | |
| fixed4 texColor = SampleSpriteTexture (IN.texcoord + fixed2(0,_MainTex_TexelSize.y*_OutlineSize)) * IN.color; | |
| fixed4 c = _OutlineColor * texColor.a; | |
| int w = ((int)(IN.texcoord.x * 100 + IN.texcoord.y * 100 + _Time.y * 5) & 1); | |
| return c*w; | |
| } | |
| ENDCG | |
| } | |
| //outline up | |
| Pass | |
| { | |
| Offset 1, 1 | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma fragment frag | |
| #pragma multi_compile _ PIXELSNAP_ON | |
| #pragma shader_feature ETC1_EXTERNAL_ALPHA | |
| v2f vert(appdata_t IN) | |
| { | |
| return vert_outline(IN); | |
| } | |
| fixed4 frag(v2f IN) : SV_Target | |
| { | |
| fixed4 texColor = SampleSpriteTexture (IN.texcoord + fixed2(0,- _MainTex_TexelSize.y* _OutlineSize)) * IN.color; | |
| fixed4 c = _OutlineColor * texColor.a; | |
| int w = ((int)(IN.texcoord.x * 100 + IN.texcoord.y * 100 + _Time.y * 5) & 1); | |
| return c*w; | |
| } | |
| ENDCG | |
| } | |
| //outline left | |
| Pass | |
| { | |
| Offset 1, 1 | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma fragment frag | |
| #pragma multi_compile _ PIXELSNAP_ON | |
| #pragma shader_feature ETC1_EXTERNAL_ALPHA | |
| v2f vert(appdata_t IN) | |
| { | |
| return vert_outline(IN); | |
| } | |
| fixed4 frag(v2f IN) : SV_Target | |
| { | |
| fixed4 texColor = SampleSpriteTexture (IN.texcoord + fixed2(_MainTex_TexelSize.x* _OutlineSize,0)) * IN.color; | |
| fixed4 c = _OutlineColor * texColor.a; | |
| int w = ((int)(IN.texcoord.x * 100 + IN.texcoord.y * 100 + _Time.y * 5) & 1); | |
| return c * w; | |
| } | |
| ENDCG | |
| } | |
| //outline right | |
| Pass | |
| { | |
| Offset 1, 1 | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma fragment frag | |
| #pragma multi_compile _ PIXELSNAP_ON | |
| #pragma shader_feature ETC1_EXTERNAL_ALPHA | |
| v2f vert(appdata_t IN) | |
| { | |
| return vert_outline(IN); | |
| } | |
| fixed4 frag(v2f IN) : SV_Target | |
| { | |
| fixed4 texColor = SampleSpriteTexture (IN.texcoord + fixed2(-_MainTex_TexelSize.x* _OutlineSize,0)) * IN.color; | |
| fixed4 c = _OutlineColor * texColor.a; | |
| int w = ((int)(IN.texcoord.x * 100 + IN.texcoord.y * 100 + _Time.y * 5) & 1); | |
| return c * w; | |
| } | |
| ENDCG | |
| } | |
| // | |
| Pass | |
| { | |
| Offset 0, 0 | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma fragment frag | |
| #pragma multi_compile _ PIXELSNAP_ON | |
| #pragma shader_feature ETC1_EXTERNAL_ALPHA | |
| v2f vert(appdata_t IN) | |
| { | |
| v2f OUT; | |
| OUT.vertex = UnityObjectToClipPos(IN.vertex); | |
| OUT.texcoord = IN.texcoord; | |
| OUT.color = IN.color * _Color; | |
| #ifdef PIXELSNAP_ON | |
| OUT.vertex = UnityPixelSnap (OUT.vertex); | |
| #endif | |
| return OUT; | |
| } | |
| fixed4 frag(v2f IN) : SV_Target | |
| { | |
| fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color; | |
| c.rgb *= c.a; | |
| return c; | |
| } | |
| ENDCG | |
| } | |
| } | |
| } |
Resources:
– wiki https://en.wikipedia.org/wiki/Marching_ants
– rectangle outline marching ants shader https://www.shadertoy.com/view/XltcR2
– 3d marching ants from uvs https://shaderfrog.com/app/view/1847
– marching ant ideas https://losingfight.com/blog/2007/08/30/an-alternate-way-to-implement-marching-ants/
– marching ants done in Flash http://www.quasimondo.com/archives/000573.php
Comparison (photoshop selection line)

Related Posts
2 Comments + Add Comment
Leave a comment
Recent posts
- Adding Real World Location to Ice Fishing Prototype
- [web tool] Image Channel Inspector : AlphaScope
- Editor Tool: Smart Recompile (don’t recompile if edit comments)
- Editor Tool: Scene Size Analyzer
- LudumDare 60: Old Tech
- uBasic Scripting Language for Unity
- GreaseMonkey+Editor Plugin: 1-Click Copy script from ChatGPT (Web) to Unity Editor (as script)
- Editor Tool: Property Watcher
- .unityignore : Hide files from Project window
- PostBuild Script to Create Single exe Standalone File
- Game Loop Designer
- Favorites in PackageManager
Recent Comments
Coin:
CUgDSbRqFcAumDSAcdKDvuXsw26VdkJe8C8WGUQHBAGS
An article by












Oooh. Nice one. I may borrow this at some point. 🙂
ashed (dotted) 2D Sprite Shapes in Unity
https://github.com/yasirkula/UnityDashedSpriteShape