Search Unity

Having trouble with outline shder

Discussion in 'Shaders' started by 5c4r3cr0w, May 23, 2019.

  1. 5c4r3cr0w

    5c4r3cr0w

    Joined:
    Mar 8, 2016
    Posts:
    35
    Hello everyone,

    I am trying to create an outline shader where outline is also controlled by an alpha cut off variable.
    Below is my code:


    Code (CSharp):
    1. Shader "Custom/fancyOutlines"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Texture",2D)="white"{}
    6.         _Color("Colour",Color)=(1,1,1,1)
    7.         _Noise("Noise",2D)="white"{}
    8.        
    9.        
    10.         _OutlineColor1("Outline_1",Color)=(1,1,1,1) //Inner Most
    11.      
    12.        
    13.         _Outline_1_Width("WidthOutline_1",Range(0.0,0.1))=0.01
    14.         _Param("Tint",Range(0,1.01))=0
    15.      
    16.     }
    17.      CGINCLUDE
    18.             #include "UnityCG.cginc"
    19.            
    20.             sampler2D _MainTex;
    21.             float4 _Color;
    22.             float4 _OutlineColor1;
    23.             sampler2D _Noise;
    24.             float _Param;
    25.             float _Outline_1_Width;
    26.         ENDCG
    27.  
    28.    SubShader
    29.    {
    30.      
    31.         Pass
    32.         {
    33.             ZWrite Off
    34.             Cull Off
    35.             Blend SrcAlpha OneMinusSrcAlpha
    36.            
    37.             Tags{"Queue"="Transparent"}
    38.            
    39.             CGPROGRAM
    40.             #pragma vertex vert
    41.             #pragma fragment frag
    42.            
    43.             struct vertexInput
    44.             {
    45.                 float4 vertex : POSITION;
    46.                 float4 coord : TEXCOORD0;
    47.                 float4 coord1 : TEXCOORD1;
    48.                 float3 normal : NORMAL;
    49.             };
    50.            
    51.             struct vertexOutput
    52.             {
    53.                 float4 pos : SV_POSITION;
    54.                 float4 uv : TEXCOORD0;
    55.                 float3 norm : NORMAL;
    56.              
    57.             };
    58.            
    59.             vertexOutput vert(vertexInput vin)
    60.             {
    61.               vertexOutput vout;
    62.               vout.uv = vin.coord;
    63.               float3 tx = vin.vertex.xyz;
    64.               vin.vertex.xyz += (vin.normal.xyz)*_Outline_1_Width;
    65.            
    66.               vout.pos = UnityObjectToClipPos(vin.vertex);
    67.              // vout.uv2 = vin.vertex;
    68.               return vout;
    69.             }
    70.            
    71.             float4 frag(vertexOutput vout):COLOR
    72.             {
    73.                //float4 res = lerp(tex2D(_Noise,vout.uv),float4(1,1,1,1),_Param);
    74.              
    75.                float4 res = tex2D(_Noise,vout.uv);
    76.                _Param = 1.01-_Param;
    77.              
    78.               // clip(vout.dc.x);
    79.              
    80.              
    81.                clip(res.a-_Param);
    82.              
    83.                return _OutlineColor1;
    84.          
    85.             }
    86.          
    87.             ENDCG
    88.            
    89.         }
    90.        
    91.         Pass
    92.         {
    93.             ZWrite On
    94.             Cull Back
    95.             Blend SrcAlpha OneMinusSrcAlpha
    96.            
    97.             Tags{"Queue"="Transparent+1"}
    98.             CGPROGRAM
    99.             #pragma vertex vert
    100.             #pragma fragment frag
    101.            
    102.             struct vertexInput
    103.             {
    104.                 float4 vertex : POSITION;
    105.                 float4 coord : TEXCOORD0;
    106.             };
    107.            
    108.             struct vertexOutput{
    109.                 float4 pos : SV_POSITION;
    110.                 float4 uv : TEXCOORD0;
    111.             };
    112.            
    113.             vertexOutput vert(vertexInput vin)
    114.             {
    115.                 vertexOutput vout;
    116.                 vout.uv = vin.coord;
    117.              
    118.                 vout.pos = UnityObjectToClipPos(vin.vertex);
    119.                
    120.                 return vout;
    121.             }
    122.             float4 frag(vertexOutput vout) : COLOR
    123.             {
    124.                 //discard;
    125.                 return tex2D(_MainTex,vout.uv) * _Color;
    126.                 //return float4(1,1,1,0);
    127.             }
    128.            
    129.             ENDCG
    130.         }
    131.    }
    132. }
    133.  
    How do I eliminate extra outline color which is being rendered on top of my mesh?
     
  2. 5c4r3cr0w

    5c4r3cr0w

    Joined:
    Mar 8, 2016
    Posts:
    35
    Ok fixed it by replacing

    Code (CSharp):
    1. Blend SrcAlpha OneMinusSrcAlpha
    to

    Code (CSharp):
    1. Blend DstAlpha OneMinusDstAlpha
    in Second Pass :)
     
  3. 5c4r3cr0w

    5c4r3cr0w

    Joined:
    Mar 8, 2016
    Posts:
    35
    Hello Again..

    Can anyone tell me how do I completely remove the main mesh and only render outlines with this shader? :)
     
  4. 5c4r3cr0w

    5c4r3cr0w

    Joined:
    Mar 8, 2016
    Posts:
    35
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You only want a silhouette, correct? You'll either need to use stencils, or a depth offset.

    stencil method:
    Render the main mesh using a shader like this:
    Code (csharp):
    1. Pass {
    2.     ColorMask 0
    3.     ZWrite Off
    4.     Stencil {
    5.         Ref 1
    6.         Pass Replace
    7.     }
    8. }
    Yes, that's the entire pass. It needs to render first.

    Then render your outline like you already are, but with this extra bit before the CGPROGRAM:
    Code (csharp):
    1. Stencil {
    2.     Ref 1
    3.     Comp NotEqual
    4. }
    Get rid of your existing second pass.

    The depth offset option works by slightly offsetting the outline back a little.
    Code (csharp):
    1. vout.pos = UnityObjectToClipPos(vin.vertex);
    2. vout.pos.z += _OutlineZOffset;
    That'll take some tweaking to get it looking like you want, and is heavily depending on how far from the camera the object is. However if you use the above pass (with the stencil related lines removed) you can get an outline that has no internal lines and doesn't require using stencils. The outline may get hidden by other nearby objects though, like the ground.

    Also, the "Queue" set in the pass's Tags {} is ignored. You can only set the Queue in the SubShader's Tags.
     
    5c4r3cr0w likes this.
  6. 5c4r3cr0w

    5c4r3cr0w

    Joined:
    Mar 8, 2016
    Posts:
    35
    Thank you very much!!!.
    It's working as expected. :)