1. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  2. Unity 2017.2 beta is now available for download.
    Dismiss Notice
  3. Unity 2017.1 is now released.
    Dismiss Notice
  4. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  5. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  6. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    Dismiss Notice

Sprite Shader with GreyScale

Discussion in 'Shaders' started by Dev6_RC, Jan 15, 2014.

  1. Dev6_RC

    Dev6_RC

    Joined:
    Dec 18, 2013
    Posts:
    46
    Hey Guys,

    I am new to shading but somehow managed to acomplish this for the new 2D Sprite system of Unity.
    You can use sliders to control the grayscalevalue :)

    If someone needs grayscale for his textures there you go: :)

    Code (csharp):
    1. Shader "Sprites/GrayScale"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Color ("Tint", Color) = (1,1,1,1)
    7.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    8.         _EffectAmount ("Effect Amount", Range (0, 1)) = 1.0
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue"="Transparent"
    16.             "IgnoreProjector"="True"
    17.             "RenderType"="Transparent"
    18.             "PreviewType"="Plane"
    19.             "CanUseSpriteAtlas"="True"
    20.         }
    21.  
    22.         Cull Off
    23.         Lighting Off
    24.         ZWrite Off
    25.         Fog { Mode Off }
    26.         Blend SrcAlpha OneMinusSrcAlpha
    27.  
    28.         Pass
    29.         {
    30.         CGPROGRAM
    31.             #pragma vertex vert
    32.             #pragma fragment frag
    33.             #pragma multi_compile DUMMY PIXELSNAP_ON
    34.             #include "UnityCG.cginc"
    35.            
    36.             struct appdata_t
    37.             {
    38.                 float4 vertex   : POSITION;
    39.                 float4 color    : COLOR;
    40.                 float2 texcoord : TEXCOORD0;
    41.             };
    42.  
    43.             struct v2f
    44.             {
    45.                 float4 vertex   : SV_POSITION;
    46.                 fixed4 color    : COLOR;
    47.                 half2 texcoord  : TEXCOORD0;
    48.             };
    49.            
    50.             fixed4 _Color;
    51.  
    52.             v2f vert(appdata_t IN)
    53.             {
    54.                 v2f OUT;
    55.                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
    56.                 OUT.texcoord = IN.texcoord;
    57.                 OUT.color = IN.color * _Color;
    58.                 #ifdef PIXELSNAP_ON
    59.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
    60.                 #endif
    61.  
    62.                 return OUT;
    63.             }
    64.  
    65.             sampler2D _MainTex;
    66.             uniform float _EffectAmount;
    67.  
    68.             fixed4 frag(v2f IN) : COLOR
    69.             {
    70.                 half4 texcol = tex2D (_MainTex, IN.texcoord);              
    71.                 texcol.rgb = lerp(texcol.rgb, dot(texcol.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);
    72.                 texcol = texcol * IN.color;
    73.                 return texcol;
    74.             }
    75.         ENDCG
    76.         }
    77.     }
    78.     Fallback "Sprites/Default"
    79. }
    80.  
    If you want to change things threw code use this:

    Code (csharp):
    1. _GAMEOBJECT_.renderer.material.SetFloat("_EffectAmount", 0.5f);
    Cheers :)
     
    Last edited: Jan 15, 2014
  2. Dev6_RC

    Dev6_RC

    Joined:
    Dec 18, 2013
    Posts:
    46
    ##EDIT##

    fixed it with:

    Code (csharp):
    1. texcol = texcol * IN.color;
     
    Last edited: Jan 15, 2014
  3. xenonsin

    xenonsin

    Joined:
    Dec 12, 2013
    Posts:
    4
    This is great! I'm wondering though if it's possible to modify the code so that parts of the original color gets permanently revealed based on a circle around some coordinates? Similar to how a fog of war shader would work, I would imagine?


    Similar to this: http://codepen.io/cwolves/pen/prvnb
     
    Dev6_RC likes this.
  4. emisael-carrera

    emisael-carrera

    Joined:
    May 2, 2014
    Posts:
    3
    Thanks a lot Dev6_RC, I was using a shader that was working well on unity editor, but on android the shader was broken, I don't know why, but the yours worked really good! Thank you a lot! :)
     
    Dev6_RC likes this.
  5. mohhad

    mohhad

    Joined:
    Jul 30, 2014
    Posts:
    7
    Cheers Bro. Great work.
     
  6. kUr4m4

    kUr4m4

    Joined:
    May 14, 2013
    Posts:
    7
    This is really awesome! But I would like to have the same shader effect on regular textures but I'm really bad at shaders...anyone have any clue?
     
  7. azmundai

    azmundai

    Joined:
    Jun 21, 2010
    Posts:
    22
    This is very cool and works great, but it doesn't seem to work with masking in the UI. I applied a material with this shader to a sprite on my canvas with a mask on top of it .. and the grayscale texture doesnt get masked. If I change material to none it masks just fine. Is this something that can be added?
     
  8. Dev6_RC

    Dev6_RC

    Joined:
    Dec 18, 2013
    Posts:
    46
    I am sorry, but I have no time ATM. If i had to guess: this shader is based on the Unity sprites shader ( with some modifications ) You could try to look into the base shader of the unity UI system and add the required features into this one. If you do so feel free to post it here! :) Help the Community! :D
     
  9. nTu4Ka

    nTu4Ka

    Joined:
    Jan 27, 2014
    Posts:
    13
    Wow! You are awesome!
     
  10. obilang

    obilang

    Joined:
    Feb 1, 2015
    Posts:
    4
    That helped me a lot~ Thank you!
     
  11. vinipc

    vinipc

    Joined:
    Jun 21, 2013
    Posts:
    6
    Thanks, this was really helpful.
    However, as noted by azmundai, it doesn't work with Unity UI's Image, so I used your shader to modify Unity's default shader and came up with this:


    Code (CSharp):
    1. Shader "Grayscale"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Color ("Tint", Color) = (1,1,1,1)
    7.      
    8.         _StencilComp ("Stencil Comparison", Float) = 8
    9.         _Stencil ("Stencil ID", Float) = 0
    10.         _StencilOp ("Stencil Operation", Float) = 0
    11.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    12.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    13.  
    14.         _ColorMask ("Color Mask", Float) = 15
    15.         _GrayscaleAmount ("Grayscale Amount", Range (0, 1)) = 1.0
    16.  
    17.         [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    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.         Stencil
    32.         {
    33.             Ref [_Stencil]
    34.             Comp [_StencilComp]
    35.             Pass [_StencilOp]
    36.             ReadMask [_StencilReadMask]
    37.             WriteMask [_StencilWriteMask]
    38.         }
    39.  
    40.         Cull Off
    41.         Lighting Off
    42.         ZWrite Off
    43.         ZTest [unity_GUIZTestMode]
    44.         Blend SrcAlpha OneMinusSrcAlpha
    45.         ColorMask [_ColorMask]
    46.  
    47.         Pass
    48.         {
    49.         CGPROGRAM
    50.             #pragma vertex vert
    51.             #pragma fragment frag
    52.  
    53.             #include "UnityCG.cginc"
    54.             #include "UnityUI.cginc"
    55.  
    56.             #pragma multi_compile __ UNITY_UI_ALPHACLIP
    57.          
    58.             struct appdata_t
    59.             {
    60.                 float4 vertex   : POSITION;
    61.                 float4 color    : COLOR;
    62.                 float2 texcoord : TEXCOORD0;
    63.             };
    64.  
    65.             struct v2f
    66.             {
    67.                 float4 vertex   : SV_POSITION;
    68.                 fixed4 color    : COLOR;
    69.                 half2 texcoord  : TEXCOORD0;
    70.                 float4 worldPosition : TEXCOORD1;
    71.             };
    72.          
    73.             fixed4 _Color;
    74.             fixed4 _TextureSampleAdd;
    75.             float4 _ClipRect;
    76.             uniform float _GrayscaleAmount;
    77.  
    78.             v2f vert(appdata_t IN)
    79.             {
    80.                 v2f OUT;
    81.                 OUT.worldPosition = IN.vertex;
    82.                 OUT.vertex = mul(UNITY_MATRIX_MVP, OUT.worldPosition);
    83.  
    84.                 OUT.texcoord = IN.texcoord;
    85.              
    86.                 #ifdef UNITY_HALF_TEXEL_OFFSET
    87.                 OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
    88.                 #endif
    89.              
    90.                 OUT.color = IN.color * _Color;
    91.                 return OUT;
    92.             }
    93.  
    94.             sampler2D _MainTex;
    95.  
    96.             fixed4 frag(v2f IN) : SV_Target
    97.             {
    98.                 half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
    99.              
    100.                 color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
    101.                 color.rgb = lerp(color.rgb, dot(color.rgb, float3(0.3, 0.59, 0.11)), _GrayscaleAmount);
    102.              
    103.                 #ifdef UNITY_UI_ALPHACLIP
    104.                 clip (color.a - 0.001);
    105.                 #endif
    106.  
    107.                 return color;
    108.             }
    109.         ENDCG
    110.         }
    111.     }
    112. }
    113.  
    Hope it helps!
     

    Attached Files:

  12. DungDajHjep

    DungDajHjep

    Joined:
    Mar 25, 2015
    Posts:
    24
    Thanks you it's Great !. Work on Android, tested !
     
  13. Dev6_RC

    Dev6_RC

    Joined:
    Dec 18, 2013
    Posts:
    46
    Nice! Everything that helps improving this shader and unity itself is appriciated! :)
     
  14. CtrlZzzz

    CtrlZzzz

    Joined:
    Aug 18, 2013
    Posts:
    2
    Waow guys, it's awesome ! Thank you very much for these two Grey Scale shader scripts.
    There are very useful !
     
  15. Nick110

    Nick110

    Joined:
    Feb 19, 2015
    Posts:
    1
    Thanks, this was really helpfull.
     
  16. harleywinks

    harleywinks

    Joined:
    Nov 14, 2014
    Posts:
    4
    Just what I needed! Thanks @Dev6_RC!

    FUN FACT: I was curious about the magic vector (0.3, 0.59, 0.11) in this line:

    Code (cg):
    1. color.rgb= lerp(color.rgb, dot(color.rgb, float3(0.3, 0.59, 0.11)), _GrayscaleAmount);
    ...they're saying something like "make the grayscale whiteness value of a color 0.3R + 0.59G + 0.11B" but where do those coefficients come from? I looked it up and it seems they come from the NTSC TV standard/the way human eyes work: ~60% of perceived luminosity comes from green, ~30% from red, ~10% from blue.
     
  17. Dev6_RC

    Dev6_RC

    Joined:
    Dec 18, 2013
    Posts:
    46
    Hey harleywinks :) Thanks for your kind reply!
    This happened a long time ago, but if I remember corectly this was the base Vector unity used in it's Sprite Shader. I used it to modify the color so the "real" Color and the "Grayscaled" Color look best :)
     
  18. sfilo

    sfilo

    Joined:
    Oct 23, 2012
    Posts:
    20
    I was just beginning to look into grayscale sprites. This made my life a lot easier. Thank you!
     
  19. dasm30

    dasm30

    Joined:
    Jun 27, 2013
    Posts:
    6
    Helloo, so no warnings, but GrayscaleAmount is not working, the image/sprite always looks gray.
     
  20. Link538

    Link538

    Joined:
    Jan 25, 2013
    Posts:
    15
    I made a Sprite/Diffuse version from the builtin shader & the grayscale version:

    Code (CSharp):
    1. // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
    2.  
    3. Shader "Sprites/GrayScale"
    4. {
    5.     Properties
    6.     {
    7.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    8.         _Color ("Tint", Color) = (1,1,1,1)
    9.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    10.         [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
    11.         [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
    12.         [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
    13.         [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
    14.         _EffectAmount ("Effect Amount", Range (0, 1)) = 1.0
    15.     }
    16.  
    17.     SubShader
    18.     {
    19.         Tags
    20.         {
    21.             "Queue"="Transparent"
    22.             "IgnoreProjector"="True"
    23.             "RenderType"="Transparent"
    24.             "PreviewType"="Plane"
    25.             "CanUseSpriteAtlas"="True"
    26.         }
    27.  
    28.         Cull Off
    29.         Lighting Off
    30.         ZWrite Off
    31.         Blend One OneMinusSrcAlpha
    32.  
    33.         CGPROGRAM
    34.         #pragma surface surf Lambert vertex:vert nofog nolightmap nodynlightmap keepalpha noinstancing
    35.         #pragma multi_compile _ PIXELSNAP_ON
    36.         #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
    37.         #include "UnitySprites.cginc"
    38.  
    39.         struct Input
    40.         {
    41.             float2 uv_MainTex;
    42.             fixed4 color;
    43.         };
    44.        
    45.         void vert (inout appdata_full v, out Input o)
    46.         {
    47.             v.vertex.xy *= _Flip.xy;
    48.  
    49.             #if defined(PIXELSNAP_ON)
    50.             v.vertex = UnityPixelSnap (v.vertex);
    51.             #endif
    52.            
    53.             UNITY_INITIALIZE_OUTPUT(Input, o);
    54.             o.color = v.color * _Color * _RendererColor;
    55.         }
    56.         uniform float _EffectAmount;
    57.  
    58.         void surf (Input IN, inout SurfaceOutput o)
    59.         {
    60.             fixed4 c = SampleSpriteTexture (IN.uv_MainTex) * IN.color;
    61.             c.rgb = lerp(c.rgb, dot(c.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);
    62.             o.Albedo = c.rgb * c.a;
    63.             o.Alpha = c.a;
    64.         }
    65.         ENDCG
    66.     }
    67.  
    68. Fallback "Sprite/Diffuse"
    69. }
    70.  
     
  21. mitdave95

    mitdave95

    Joined:
    Jun 17, 2016
    Posts:
    1
    Any idea how to apply different grayscale amount to multiple sprites?
     
  22. jeffreyschoch

    jeffreyschoch

    Joined:
    Jan 21, 2015
    Posts:
    1,701
    Assign the material to the sprite at runtime, which will create a material instance.

    Add the [PerRendererData] attribute to the _EffectAmount property in the shader, then you can change each sprite at runtime without instantiating the material:
    Code (CSharp):
    1. public float effectAmount;
    2.  
    3. private MaterialPropertyBlock propertyBlock;
    4. private SpriteRenderer spriteRenderer;
    5.  
    6. private void Awake()
    7. {
    8.     spriteRenderer = GetComponent<SpriteRenderer>();
    9.     propertyBlock = new MaterialPropertyBlock();
    10. }
    11.  
    12. private void Start()
    13. {
    14.     if(spriteRenderer != null)
    15.     {
    16.         spriteRenderer.GetPropertyBlock(propertyBlock);
    17.         propertyBlock.SetFloat("_EffectAmount", effectAmount);
    18.         spriteRenderer.SetPropertyBlock(propertyBlock);
    19.     }
    20. }
     
    Last edited: Jun 21, 2017
  23. ZNT_Terror

    ZNT_Terror

    Joined:
    Oct 22, 2014
    Posts:
    1
    You can use a MaterialPropertyBlock to change indivual instances without instancing the material multiple times.
     
    jeffreyschoch likes this.
  24. jeffreyschoch

    jeffreyschoch

    Joined:
    Jan 21, 2015
    Posts:
    1,701
    That's true. You'll also need to give the "_EffectAmount" the [PerRendererData] attribute I believe. I'll edit my example for that method since it's definitely better.