Search Unity

Sprite Tint Shader, Not Multiplied

Discussion in 'Shaders' started by DougMcFarlane, Mar 20, 2017.

  1. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    This question is mainly for 2D sprites in the new UI system.

    Using the following grey-scale button texture (the top color is white):
    upload_2017-3-20_16-23-26.png

    If I apply a tint / color of RGB(205, 205, 255), I get this result:
    (the tint color is multiplied by the texture colors.
    The result is replacing all while values with the tint color, and the others progressively darker)
    upload_2017-3-20_16-24-18.png

    This kind of works to dynamically change the button color, but it isn't flexible / predictable enough.
    I want the tint color to be the middle color, not the highlight color.

    It would be better to supply a source grey-scale image of:
    upload_2017-3-20_16-29-15.png

    Where the grey color of RGB(128,128,128) (middle of the three greys in the pic) is substituted for the tint color. Darker greys get darker, brighter ones get brighter.

    For example, this would be the result of setting tint color to RGB(110, 110, 255) (now the center / main color):
    upload_2017-3-20_16-32-42.png

    Is this difficult to do? Do I need a custom shader? Is this a blend mode? (if so, how do I change it?)
    Can the shader just multiply the texture color by the tint color, then multiple that by two?
    I've never created a shader, so I don't know the syntax for this.

    Any help or tips would be appreciated! Thanks.
     

    Attached Files:

    Last edited: Mar 20, 2017
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    What you want a Photoshop style "overlay", for which you need a custom shader.

    The cheap version of this is the 2x multiply, which is literally "col * tint * 2". This is what many of Unity's particle shaders do. This will make middle grey match the color, but whites won't necessarily go white.

    An actual overlay is fairly complex by comparison, but you can find examples of it online. Look for "Photoshop HLSL".
     
  3. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    Thanks for your help, @bgolus.
    I just did as you suggested - multiplied the color by two (as I asked in my question).

    It seems to work - I included the shader below.
    Wow, the shader language seems unnecessarily complicated. More C like than C#.

    But now the shader doesn't use the uGui Image control's 'Color' property, yet it uses it's 'Souce Image' property.
    I have to set the color via the material. I hope this doesn't require a new draw call for each color I use.

    Code (CSharp):
    1. Shader "Custom/GUI" {
    2.  
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.        _MainTex ("Texture", 2D) = "white" {}
    6.     }
    7.  
    8.     SubShader {
    9.         Pass {
    10.             CGPROGRAM
    11.             #pragma vertex vert            
    12.             #pragma fragment frag
    13.  
    14.             struct vertInput {
    15.                 float4 vertex : POSITION;        // vertex position
    16.                 float2 uv : TEXCOORD0;            // texture coordinate
    17.             };
    18.  
    19.             struct vertOutput {
    20.                 float2 uv : TEXCOORD0;            // texture coordinate
    21.                 float4 vertex : SV_POSITION;    // clip space position
    22.             };
    23.  
    24.             // vertex shader
    25.             vertOutput vert (vertInput v) {
    26.                 vertOutput o;
    27.                 // transform position to clip space (multiply with model*view*projection matrix)
    28.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);  
    29.                 // just pass the texture coordinate
    30.                 o.uv = v.uv;                              
    31.                 return o;
    32.             }
    33.  
    34.             sampler2D _MainTex;
    35.             fixed4 _Color;
    36.  
    37.             fixed4 frag(vertOutput output) : COLOR {
    38.                 fixed4 col = tex2D(_MainTex, output.uv);
    39.                 return col * _Color * 2.0;
    40.             }        
    41.  
    42.             ENDCG
    43.         }
    44.     }
    45. }
    46.  
    47.  
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
  5. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    Image components color property sets vertex color. Let's it preserve batching if possible.
     
  6. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    It makes sense that it is setting custom vertex colors I suppose.
    But I've tried a lot of examples to use the vertex color (as opposed to a separate color), but no luck.
    The result is mostly blank images. I think I need to set the shader's variables to specific names for the Image class to reference them properly.
    Is there a copy of the default UI Image shader somewhere for me to reference?

    Again, wow this is a difficult subject!
    Thanks,
     
  7. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    I found a copy of the existing default UI shader (might not be the latest one).
    A simple edit to double the color value was all that was needed.
    Works like a charm now!

    Code (CSharp):
    1. Shader "Custom/GUI" {
    2.     Properties
    3.     {
    4.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    5.         _Color ("Tint", Color) = (1,1,1,1)
    6.        
    7.         _StencilComp ("Stencil Comparison", Float) = 8
    8.         _Stencil ("Stencil ID", Float) = 0
    9.         _StencilOp ("Stencil Operation", Float) = 0
    10.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    11.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    12.  
    13.         _ColorMask ("Color Mask", Float) = 15
    14.     }
    15.  
    16.     SubShader
    17.     {
    18.         Tags
    19.         {
    20.             "Queue"="Transparent"
    21.             "IgnoreProjector"="True"
    22.             "RenderType"="Transparent"
    23.             "PreviewType"="Plane"
    24.             "CanUseSpriteAtlas"="True"
    25.         }
    26.        
    27.         Stencil
    28.         {
    29.             Ref [_Stencil]
    30.             Comp [_StencilComp]
    31.             Pass [_StencilOp]
    32.             ReadMask [_StencilReadMask]
    33.             WriteMask [_StencilWriteMask]
    34.         }
    35.  
    36.         Cull Off
    37.         Lighting Off
    38.         ZWrite Off
    39.         ZTest [unity_GUIZTestMode]
    40.         Fog { Mode Off }
    41.         Blend SrcAlpha OneMinusSrcAlpha
    42.         ColorMask [_ColorMask]
    43.  
    44.         Pass
    45.         {
    46.         CGPROGRAM
    47.             #pragma vertex vert
    48.             #pragma fragment frag
    49.             #include "UnityCG.cginc"
    50.            
    51.             struct appdata_t
    52.             {
    53.                 float4 vertex   : POSITION;
    54.                 float4 color    : COLOR;
    55.                 float2 texcoord : TEXCOORD0;
    56.             };
    57.  
    58.             struct v2f
    59.             {
    60.                 float4 vertex   : SV_POSITION;
    61.                 fixed4 color    : COLOR;
    62.                 half2 texcoord  : TEXCOORD0;
    63.             };
    64.            
    65.             fixed4 _Color;
    66.  
    67.             v2f vert(appdata_t IN)
    68.             {
    69.                 v2f OUT;
    70.                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
    71.                 OUT.texcoord = IN.texcoord;
    72. #ifdef UNITY_HALF_TEXEL_OFFSET
    73.                 OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
    74. #endif
    75.                 OUT.color = IN.color * _Color;
    76.                 return OUT;
    77.             }
    78.  
    79.             sampler2D _MainTex;
    80.  
    81.             fixed4 frag(v2f IN) : SV_Target
    82.             {
    83.                 half4 color = tex2D(_MainTex, IN.texcoord) * IN.color * 2.0;  // Changed to double the color value
    84.                 clip (color.a - 0.01);
    85.                 return color;
    86.             }
    87.         ENDCG
    88.         }
    89.     }
    90. }