Search Unity

Shader for sprite clipping

Discussion in 'Shaders' started by Khaled-Khair, Apr 19, 2014.

  1. Khaled-Khair

    Khaled-Khair

    Joined:
    Jun 24, 2013
    Posts:
    9
    I am trying to create a shader that can be used to clip 2D sprites in a game, I found this shader on the internet :
    Code (csharp):
    1. Shader "Sprites/ClipArea"
    2. {
    3. Properties
    4. {
    5.     _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {}
    6.     _Length ("Length", Range(0.0, 1.0)) = 1.0
    7.     _Width ("Width", Range(0.0, 1.0)) = 0.5
    8.  }
    9.  
    10. SubShader
    11. {
    12.     LOD 200
    13.  
    14.     Tags
    15.     {
    16.         "Queue" = "Transparent"
    17.         "IgnoreProjector" = "True"
    18.         "RenderType" = "Transparent"
    19.     }
    20.  
    21.     Pass
    22.     {
    23.         Cull Off
    24.         Lighting Off
    25.         ZWrite Off
    26.         Offset -1, -1
    27.         Fog { Mode Off }
    28.         ColorMask RGB
    29.         Blend SrcAlpha OneMinusSrcAlpha
    30.  
    31.         CGPROGRAM
    32.         #pragma vertex vert
    33.         #pragma fragment frag
    34.  
    35.         #include "UnityCG.cginc"
    36.  
    37.         sampler2D _MainTex;
    38.         float4 _MainTex_ST;
    39.         float _Length;
    40.         float _Width;
    41.  
    42.         struct appdata_t
    43.         {
    44.             float4 vertex : POSITION;
    45.             float2 texcoord : TEXCOORD0;
    46.         };
    47.  
    48.         struct v2f
    49.         {
    50.             float4 vertex : POSITION;
    51.             float2 texcoord : TEXCOORD0;
    52.         };
    53.  
    54.         v2f vert (appdata_t v)
    55.         {
    56.             v2f o;
    57.             o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    58.             o.texcoord = v.texcoord;
    59.             return o;
    60.         }
    61.  
    62.         half4 frag (v2f IN) : COLOR
    63.         {
    64.             if ((IN.texcoord.x<0) || (IN.texcoord.x>_Width) || (IN.texcoord.y<0) || (IN.texcoord.y>_Length))
    65.  
    66.             {
    67.                 half4 colorTransparent = half4(0,0,0,0) ;
    68.                 return  colorTransparent ;
    69.             }
    70.             return tex2D(_MainTex, IN.texcoord);
    71.         }
    72.         ENDCG
    73.     }
    74. }
    75. }
    which works perfectly on single sprites, but I am using sprite sheets, divided by Unity Sprite editor.

    What I was able to figure out is that the TEXCOORD0 the shader is receiving is covering the whole sprite sheet, not the sprite being rendered. I searched for a way to get the current sprite rect inside the shader but couldn't find anything. Any help will be much appreciated.
     
    Saicopate likes this.
  2. Khaled-Khair

    Khaled-Khair

    Joined:
    Jun 24, 2013
    Posts:
    9
    Well, after pulling my hair for three days, I managed to find a workaround. After searching more about how shaders work and there role in the pipeline, I realized that the sprite rect info will probably be not available in the shader for one simple reason, the functionality of almost all shaders (except mine) does not require this info, because the job of the shader is to take a vertex, modify its position (if needed) through the vertex function and then decide its pixel colour through the fragment function, it does not care about the whole sprite, it only needs to lookup the pixel colour for a certain vertex from the texture using its texture coordinates. I am sure this is trivial info for people working in shaders, but it took me time to realize it ( This was my first ever shader). So as a workaround I had to use the shader properties to pass the MinX and MaxX of the current sprite the shader is working on in the sprite sheet, so the shader now looks like this:
    Code (csharp):
    1. Shader "Sprites/ClipArea"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {}
    6.         _Fill ("Fill", Range(0.0, 1.0)) = 1.0
    7.         _MinX ("MinX", Float) = 0
    8.         _MaxX ("MaxX", Float) = 1
    9.      }
    10.  
    11.     SubShader
    12.     {
    13.         LOD 200
    14.  
    15.         Tags
    16.         {
    17.             "Queue" = "Transparent"
    18.             "IgnoreProjector" = "True"
    19.             "RenderType" = "Transparent"
    20.         }
    21.  
    22.         Pass
    23.         {
    24.             Cull Off
    25.             Lighting Off
    26.             ZWrite Off
    27.             Offset -1, -1
    28.             Fog { Mode Off }
    29.             ColorMask RGB
    30.             Blend SrcAlpha OneMinusSrcAlpha
    31.  
    32.             CGPROGRAM
    33.             #pragma vertex vert
    34.             #pragma fragment frag
    35.  
    36.             #include "UnityCG.cginc"
    37.  
    38.             sampler2D _MainTex;
    39.             float4 _MainTex_ST;
    40.             float _MinX;
    41.             float _MaxX;
    42.             float _Fill;
    43.  
    44.             struct appdata_t
    45.             {
    46.                 float4 vertex : POSITION;
    47.                 float2 texcoord : TEXCOORD0;
    48.             };
    49.  
    50.             struct v2f
    51.             {
    52.                 float4 vertex : POSITION;
    53.                 float2 texcoord : TEXCOORD0;
    54.             };
    55.  
    56.             v2f vert (appdata_t v)
    57.             {
    58.                 v2f o;
    59.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    60.                 o.texcoord = v.texcoord;
    61.                 return o;
    62.             }
    63.  
    64.             half4 frag (v2f IN) : COLOR
    65.             {
    66.             if ((IN.texcoord.x<_MinX)|| (IN.texcoord.x>(_MinX+_Fill*(_MaxX-_MinX))))
    67.                 {
    68.                     half4 colorTransparent = half4(0,0,0,0) ;
    69.                     return  colorTransparent ;
    70.                 }
    71.                 return tex2D(_MainTex, IN.texcoord);
    72.             }
    73.             ENDCG
    74.         }
    75.     }
    76. }
    To use this shader, you need to create a material that uses it, then use that material in the SpriteRenderer, you can change the Fill amount, MinX , and MaxX from the inspector, or call the spriteRenderer.material.setFloat(property, value) from code.

    I then faced another issue with animated sprites, I had to keep updating the MinX and MaxX on every frame, but when I did it in the Update function the animation started flickering, and thats because the update was being called after the sprite is rendered, so I had to use the Main Camera OnPreRender event to update the material properties.

    Maybe there is a better way to achieve all this but this is the best I could come up with, and I hope this will benefit someone trying to achieve the same effect.
     
  3. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    This solution not working for me. As a result it shows white material and when I select shader for it Sprites/ClipArea, it shows images white also. Please help me to come out of this.