foreword
Today we will implement a simple 2D sprite map stroke effect, the effect picture is as follows:
Preparation:
First, we open unity to create a new scene, import a picture, and set the picture as a Sprite type, as shown in the figure:
   
Implementation idea:
The idea is actually very simple. You can judge whether there is a value of transparency of 0 around the pixel. If there is, it means that the pixel is on the edge.
So we need to turn on alpha blend, namely: Blend SrcAlpha OneMinusSrcAlpha, and join the rendering queue,
<pre> Tags {<!-- --> "Queue" = "Transparent" } Blend SrcAlpha OneMinusSrcAlpha
Let’s start writing the fragment shader. The vertex shader is a conventional vertex coordinate transformation. I won’t paste the code here. Let’s mainly look at the fragment shader:
<pre> // ---------------------------【Fragment Shader】--------------------------- fixed4 frag ( VertexOutput i ) : SV_Target {<!-- --> fixed4 col = tex2D ( _MainTex , i . uv ) ; // Sample 4 points around float2 up_uv = i . uv + float2 ( 0 , 1 ) * _lineWidth * _MainTex_TexelSize . xy ; float2 down_uv = i . uv + float2 ( 0 , - 1 ) * _lineWidth * _MainTex_TexelSize . xy ; float2 left_uv = i . uv + float2 ( - 1 , 0 ) * _lineWidth * _MainTex_TexelSize . xy ; float2 right_uv = i . uv + float2 ( 1 , 0 ) * _lineWidth * _MainTex_TexelSize . xy ; // If there is a point whose transparency is 0, it means it is an edge float w = tex2D ( _MainTex , up_uv ) . a * tex2D ( _MainTex , down_uv ) . a * tex2D ( _MainTex , left_uv ) . a * tex2D ( _MainTex , right_uv ) . a ; if ( w == 0 ) {<!-- --> col . rgb = _lineColor ; } return col ; }
_MainTex_TexelSize: Texture pixel size
We can use this property to calculate the surrounding (up, down, left, and right) pixel coordinates, and then judge whether there is a value with transparency of 0. If it is 0, returns the border color.
The effect is as follows:
Although we have implemented this function, if we observe carefully, we will find that the edges are jagged and not smooth. We can optimize and use interpolation to smooth the transition,
The final complete Shader code is as follows:
<pre> // ---------------------------【2D stroke effect】--------------- ------------ // create by Longevity but Drunkard Shader "lcl/shader2D/outline" {<!-- --> Properties {<!-- --> _MainTex ( "Texture" , 2D ) = "white" {<!-- --> } _lineWidth ( "lineWidth" , Range ( 0 , 10 ) ) = 1 _lineColor ( "lineColor" , color ) = ( 1 , 1 , 1 , 1 ) } // ---------------------------【Subshader】---------------- ----------- SubShader {<!-- --> // The rendering queue adopts transparent Tags {<!-- --> "Queue" = "Transparent" } Blend SrcAlpha OneMinusSrcAlpha Pass {<!-- --> CGPROGRAM # pragma vertex vert # pragma fragment frag #include "UnityCG.cginc" //Vertex shader input structure structure VertexInput {<!-- --> float4 vertex : POSITION ; float2 uv : TEXCOORD0 ; } ; //Vertex shader output structure structure VertexOutput {<!-- --> float2 uv : TEXCOORD0 ; float4 vertex : SV_POSITION ; } ; // --------------------------【Vertex Shader】---------------- ----------- VertexOutput vert ( VertexInput v ) {<!-- --> VertexOutput o ; o . vertex = UnityObjectToClipPos ( v . vertex ) ; o . uv = v . uv ; return o ; } sampler2D _MainTex ; float4 _MainTex_TexelSize ; float _lineWidth ; float4 _lineColor ; // ---------------------------【Fragment Shader】--------------------------- fixed4 frag ( VertexOutput i ) : SV_Target {<!-- --> fixed4 col = tex2D ( _MainTex , i . uv ) ; // Sample 4 points around float2 up_uv = i . uv + float2 ( 0 , 1 ) * _lineWidth * _MainTex_TexelSize . xy ; float2 down_uv = i . uv + float2 ( 0 , - 1 ) * _lineWidth * _MainTex_TexelSize . xy ; float2 left_uv = i . uv + float2 ( - 1 , 0 ) * _lineWidth * _MainTex_TexelSize . xy ; float2 right_uv = i . uv + float2 ( 1 , 0 ) * _lineWidth * _MainTex_TexelSize . xy ; // If there is a point whose transparency is 0, it means it is an edge float w = tex2D ( _MainTex , up_uv ) . a * tex2D ( _MainTex , down_uv ) . a * tex2D ( _MainTex , left_uv ) . a * tex2D ( _MainTex , right_uv ) . a ; // if(w == 0){<!-- --> // col.rgb = _lineColor; // } // Interpolate with the original image col . rgb = lerp ( _lineColor , col . rgb , w ) ; return col ; } ENDCG } } }
Comparison of final renderings:
at last
Finally welcome to my
GitHub
Star, thank you! There are some special effect demos that I usually realize in the process of learning unity shader.