Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Sprite with stencil mask and outline

Discussion in '2D' started by luispedrofonseca, May 8, 2019.

  1. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    938
    Hi, I'm trying to combine two shaders on the same sprite but unfortunately after a lot of trial and error I can't seem to figure it out.

    Basically I have two shaders, one to mask a sprite using the stencil buffer, and another that applies an outline to a sprite.
    Code (csharp):
    1.  
    2. Shader "Sprites/Custom/SpriteMasked"
    3. {
    4.    Properties
    5.    {
    6.       [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
    7.       _Color("Tint", Color) = (1,1,1,1)
    8.       [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
    9.       [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
    10.       [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
    11.       [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
    12.       [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
    13.  
    14.       // Add values to determine if outlining is enabled and outline color.
    15.       [PerRendererData] _Outline("Outline", Float) = 0
    16.       [PerRendererData] _OutlineColor("Outline Color", Color) = (1,1,1,1)
    17.       [PerRendererData] _OutlineSize("Outline Size", int) = 1
    18.    }
    19.  
    20.     SubShader
    21.    {
    22.       Tags
    23.         {
    24.             "Queue" = "Transparent"
    25.             "IgnoreProjector" = "True"
    26.             "RenderType" = "Transparent"
    27.             "PreviewType" = "Plane"
    28.             "CanUseSpriteAtlas" = "True"
    29.         }
    30.  
    31.       Cull Off
    32.       Lighting Off
    33.       ZWrite Off
    34.       Fog{ Mode Off }
    35.       Blend One OneMinusSrcAlpha
    36.  
    37.       Pass
    38.        {
    39.          Stencil
    40.          {
    41.                 Ref 2
    42.                 Comp equal
    43.                 Pass replace
    44.           }
    45.  
    46.             CGPROGRAM
    47.             #pragma vertex vert
    48.             #pragma fragment frag
    49.             #pragma multi_compile DUMMY PIXELSNAP_ON
    50.             #include "UnityCG.cginc"
    51.    
    52.             struct appdata_t
    53.             {
    54.                 float4 vertex   : POSITION;
    55.                 float4 color    : COLOR;
    56.                 float2 texcoord : TEXCOORD0;
    57.             };
    58.    
    59.             struct v2f
    60.             {
    61.                 float4 vertex   : SV_POSITION;
    62.                 fixed4 color : COLOR;
    63.                 half2 texcoord  : TEXCOORD0;
    64.             };
    65.    
    66.             fixed4 _Color;
    67.    
    68.             v2f vert(appdata_t IN)
    69.             {
    70.                 v2f OUT;
    71.                 OUT.vertex = UnityObjectToClipPos(IN.vertex);
    72.                 OUT.texcoord = IN.texcoord;
    73.                 OUT.color = IN.color * _Color;
    74.                 #ifdef PIXELSNAP_ON
    75.                 OUT.vertex = UnityPixelSnap(OUT.vertex);
    76.                 #endif
    77.        
    78.                 return OUT;
    79.             }
    80.    
    81.             sampler2D _MainTex;
    82.    
    83.             fixed4 frag(v2f IN) : SV_Target
    84.             {
    85.                 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
    86.                 c.rgb *= c.a;
    87.                 return c;
    88.             }
    89.             ENDCG
    90.        }
    91.    }
    92. }
    93.  
    Code (csharp):
    1.  
    2. Shader "Sprites/Custom/SpriteMaskedOutline"
    3. {
    4.    Properties
    5.    {
    6.       [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    7.       _Color ("Tint", Color) = (1,1,1,1)
    8.       [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    9.       [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
    10.       [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
    11.       [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
    12.       [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
    13.  
    14.       // Add values to determine if outlining is enabled and outline color.
    15.       _Outline("Outline", Float) = 1
    16.       _OutlineColor("Outline Color", Color) = (1,1,1,1)
    17.       _OutlineSize("Outline Size", int) = 10
    18.    }
    19.  
    20.    SubShader
    21.    {
    22.       Tags
    23.       {
    24.          "Queue"="Transparent"
    25.          "IgnoreProjector"="True"
    26.          "RenderType"="Transparent"
    27.          "PreviewType"="Plane"
    28.          "CanUseSpriteAtlas"="True"
    29.       }
    30.  
    31.       Cull Off
    32.       Lighting Off
    33.       ZWrite Off
    34.       Fog{ Mode Off }
    35.       Blend One OneMinusSrcAlpha
    36.  
    37.       Pass
    38.       {
    39.         CGPROGRAM
    40.          #pragma vertex SpriteVert
    41.          #pragma fragment frag
    42.          #pragma target 2.0
    43.          #pragma multi_compile_instancing
    44.          #pragma multi_compile _ PIXELSNAP_ON
    45.          #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
    46.          #include "UnitySprites.cginc"
    47.  
    48.          float _Outline;
    49.          fixed4 _OutlineColor;
    50.          int _OutlineSize;
    51.          float4 _MainTex_TexelSize;
    52.  
    53.          fixed4 frag(v2f IN) : SV_Target
    54.          {
    55.             fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color;
    56.                
    57.             // If outline is enabled and there is a pixel, try to draw an outline.
    58.             if (_Outline > 0 && c.a != 0) {
    59.                float totalAlpha = 1.0;
    60.  
    61.                [unroll(16)]
    62.                for (int i = 1; i < _OutlineSize + 1; i++) {
    63.                   fixed4 pixelUp = tex2D(_MainTex, IN.texcoord + fixed2(0, i * _MainTex_TexelSize.y));
    64.                   fixed4 pixelDown = tex2D(_MainTex, IN.texcoord - fixed2(0,i *  _MainTex_TexelSize.y));
    65.                   fixed4 pixelRight = tex2D(_MainTex, IN.texcoord + fixed2(i * _MainTex_TexelSize.x, 0));
    66.                   fixed4 pixelLeft = tex2D(_MainTex, IN.texcoord - fixed2(i * _MainTex_TexelSize.x, 0));
    67.  
    68.                   totalAlpha = totalAlpha * pixelUp.a * pixelDown.a * pixelRight.a * pixelLeft.a;
    69.                }
    70.  
    71.                if (totalAlpha == 0) {
    72.                   c.rgba = fixed4(1, 1, 1, 1) * _OutlineColor;
    73.                }
    74.             }
    75.  
    76.             c.rgb *= c.a;
    77.  
    78.             return c;
    79.          }
    80.       ENDCG
    81.       }
    82.    }
    83. }
    84.  
    The image attached shows what I'm getting and what I'd like to get.

    So basically my question is, how can I apply the outline shader with the results that I get from the stencil shader (combining the two)?
     

    Attached Files:

    juelzsantana123 likes this.
  2. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    938
    Bump! I've also included an UnityPackage that has a barebones sample scene that includes both shaders and should make it easier to visualize what I'm going for. Any hints?
     

    Attached Files: