Search Unity

Unity UI [WIKI] Drawing an UI element using UnityEngine.Gradient

Discussion in 'Unity UI (uGUI) & TextMesh Pro' started by aybe, Apr 8, 2019.

  1. aybe

    aybe

    Joined:
    May 24, 2015
    Posts:
    104
    I needed a way to draw some UI using a gradient, like a progress bar for instance:

    Unity_2019-04-08_21-28-45.png

    Sharing this with you guys,
    • there's a custom editor for the shader
    • works exactly like UnityEngine.Gradient does (8 colors max)
    • it's a 1:1 copy of Unity UI Default shader + gradient added
    • it only does blend currently but it's probably what most people are looking for anyway
    Easier said than done (damn float1 silent cast :mad:) but it's finally here :).

    Part 1:

    Code (CSharp):
    1. using JetBrains.Annotations;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. // ReSharper disable once CheckNamespace
    6.  
    7. [UsedImplicitly]
    8. public class HiddenDrawer : MaterialPropertyDrawer
    9. {
    10.     public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
    11.     {
    12.     }
    13.  
    14.     public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
    15.     {
    16.         return -EditorGUIUtility.standardVerticalSpacing;
    17.     }
    18. }
    19.  
    Part 2:

    Code (CSharp):
    1. using System;
    2. using System.Linq;
    3. using JetBrains.Annotations;
    4. using UnityEditor;
    5. using UnityEngine;
    6.  
    7. // ReSharper disable once CheckNamespace
    8. // ReSharper disable once InconsistentNaming
    9. [UsedImplicitly]
    10. public class UIGradientShaderGUI : ShaderGUI
    11. {
    12.     public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    13.     {
    14.         base.OnGUI(materialEditor, properties);
    15.      
    16.         EditorGUILayout.Space();
    17.  
    18.         var material = materialEditor.target as Material;
    19.         if (material == null)
    20.             throw new ArgumentNullException(nameof(material));
    21.  
    22.         var colorKeys = Enumerable
    23.             .Range(0, material.GetInt("_Colors"))
    24.             .Select((s, t) => new GradientColorKey(material.GetColor($"_Color{t}"), material.GetFloat($"_ColorTime{t}")))
    25.             .ToArray();
    26.  
    27.         var alphaKeys = Enumerable
    28.             .Range(0, material.GetInt("_Alphas"))
    29.             .Select((s, t) => new GradientAlphaKey(material.GetFloat($"_Alpha{t}"), material.GetFloat($"_AlphaTime{t}")))
    30.             .ToArray();
    31.  
    32.         var gradient = new Gradient();
    33.         gradient.SetKeys(colorKeys, alphaKeys);
    34.  
    35.         EditorGUI.BeginChangeCheck();
    36.  
    37.         var field = EditorGUILayout.GradientField("Gradient", gradient);
    38.  
    39.         if (!EditorGUI.EndChangeCheck())
    40.             return;
    41.  
    42.         for (var i = 0; i < 8; i++)
    43.         {
    44.             material.SetColor($"_Color{i}", Color.magenta);
    45.             material.SetFloat($"_ColorTime{i}", -1.0f);
    46.             material.SetFloat($"_Alpha{i}", -1.0f);
    47.             material.SetFloat($"_AlphaTime{i}", -1.0f);
    48.         }
    49.  
    50.         for (var i = 0; i < field.colorKeys.Length; i++)
    51.         {
    52.             material.SetColor($"_Color{i}", field.colorKeys[i].color);
    53.             material.SetFloat($"_ColorTime{i}", field.colorKeys[i].time);
    54.         }
    55.  
    56.         for (var i = 0; i < field.alphaKeys.Length; i++)
    57.         {
    58.             material.SetFloat($"_Alpha{i}", field.alphaKeys[i].alpha);
    59.             material.SetFloat($"_AlphaTime{i}", field.alphaKeys[i].time);
    60.         }
    61.  
    62.         material.SetInt("_Colors", field.colorKeys.Length);
    63.  
    64.         material.SetInt("_Alphas", field.alphaKeys.Length);
    65.  
    66.         EditorUtility.SetDirty(material);
    67.     }
    68. }
    69.  
    Part 3:

    Code (CSharp):
    1. // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
    2.  
    3. Shader "UI Gradient"
    4. {
    5.     Properties
    6.     {
    7.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    8.         _Color ("Tint", Color) = (1,1,1,1)
    9.  
    10.         _StencilComp ("Stencil Comparison", Float) = 8
    11.         _Stencil ("Stencil ID", Float) = 0
    12.         _StencilOp ("Stencil Operation", Float) = 0
    13.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    14.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    15.  
    16.         _ColorMask ("Color Mask", Float) = 15
    17.  
    18.         [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    19.      
    20.         [Hidden] _Color0 ("Color 0", Color) = (1, 1, 1, 1)
    21.         [Hidden] _Color1 ("Color 1", Color) = (1, 1, 1, 1)
    22.         [Hidden] _Color2 ("Color 2", Color) = (1, 1, 1, 1)
    23.         [Hidden] _Color3 ("Color 3", Color) = (1, 1, 1, 1)
    24.         [Hidden] _Color4 ("Color 4", Color) = (1, 1, 1, 1)
    25.         [Hidden] _Color5 ("Color 5", Color) = (1, 1, 1, 1)
    26.         [Hidden] _Color6 ("Color 6", Color) = (1, 1, 1, 1)
    27.         [Hidden] _Color7 ("Color 7", Color) = (1, 1, 1, 1)
    28.      
    29.         [Hidden] _ColorTime0 ("Color Time 0", Float) = 0
    30.         [Hidden] _ColorTime1 ("Color Time 1", Float) = 0
    31.         [Hidden] _ColorTime2 ("Color Time 2", Float) = 0
    32.         [Hidden] _ColorTime3 ("Color Time 3", Float) = 0
    33.         [Hidden] _ColorTime4 ("Color Time 4", Float) = 0
    34.         [Hidden] _ColorTime5 ("Color Time 5", Float) = 0
    35.         [Hidden] _ColorTime6 ("Color Time 6", Float) = 0
    36.         [Hidden] _ColorTime7 ("Color Time 7", Float) = 0
    37.  
    38.         [Hidden] _Colors ("Colors", Int) = 0
    39.          
    40.         [Hidden] _Alpha0 ("Alpha 0", Float) = 0
    41.         [Hidden] _Alpha1 ("Alpha 1", Float) = 0
    42.         [Hidden] _Alpha2 ("Alpha 2", Float) = 0
    43.         [Hidden] _Alpha3 ("Alpha 3", Float) = 0
    44.         [Hidden] _Alpha4 ("Alpha 4", Float) = 0
    45.         [Hidden] _Alpha5 ("Alpha 5", Float) = 0
    46.         [Hidden] _Alpha6 ("Alpha 6", Float) = 0
    47.         [Hidden] _Alpha7 ("Alpha 7", Float) = 0
    48.  
    49.         [Hidden] _AlphaTime0 ("Alpha Time 0", Float) = 0
    50.         [Hidden] _AlphaTime1 ("Alpha Time 1", Float) = 0
    51.         [Hidden] _AlphaTime2 ("Alpha Time 2", Float) = 0
    52.         [Hidden] _AlphaTime3 ("Alpha Time 3", Float) = 0
    53.         [Hidden] _AlphaTime4 ("Alpha Time 4", Float) = 0
    54.         [Hidden] _AlphaTime5 ("Alpha Time 5", Float) = 0
    55.         [Hidden] _AlphaTime6 ("Alpha Time 6", Float) = 0
    56.         [Hidden] _AlphaTime7 ("Alpha Time 7", Float) = 0
    57.  
    58.         [Hidden] _Alphas ("Alphas", Int) = 0
    59.     }
    60.  
    61.     SubShader
    62.     {
    63.         Tags
    64.         {
    65.             "Queue"="Transparent"
    66.             "IgnoreProjector"="True"
    67.             "RenderType"="Transparent"
    68.             "PreviewType"="Plane"
    69.             "CanUseSpriteAtlas"="True"
    70.         }
    71.  
    72.         Stencil
    73.         {
    74.             Ref [_Stencil]
    75.             Comp [_StencilComp]
    76.             Pass [_StencilOp]
    77.             ReadMask [_StencilReadMask]
    78.             WriteMask [_StencilWriteMask]
    79.         }
    80.  
    81.         Cull Off
    82.         Lighting Off
    83.         ZWrite Off
    84.         ZTest [unity_GUIZTestMode]
    85.         Blend SrcAlpha OneMinusSrcAlpha
    86.         ColorMask [_ColorMask]
    87.  
    88.         Pass
    89.         {
    90.             Name "Default"
    91.         CGPROGRAM
    92.             #pragma vertex vert
    93.             #pragma fragment frag
    94.             #pragma target 2.0
    95.  
    96.             #include "UnityCG.cginc"
    97.             #include "UnityUI.cginc"
    98.  
    99.             #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
    100.             #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
    101.  
    102.             struct appdata_t
    103.             {
    104.                 float4 vertex   : POSITION;
    105.                 float4 color    : COLOR;
    106.                 float2 texcoord : TEXCOORD0;
    107.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    108.             };
    109.  
    110.             struct v2f
    111.             {
    112.                 float4 vertex   : SV_POSITION;
    113.                 fixed4 color    : COLOR;
    114.                 float2 texcoord  : TEXCOORD0;
    115.                 float4 worldPosition : TEXCOORD1;
    116.                 UNITY_VERTEX_OUTPUT_STEREO
    117.             };
    118.  
    119.             sampler2D _MainTex;
    120.             fixed4 _Color;
    121.             fixed4 _TextureSampleAdd;
    122.             float4 _ClipRect;
    123.             float4 _MainTex_ST;
    124.  
    125.             float4 _Color0, _Color1, _Color2, _Color3, _Color4, _Color5, _Color6, _Color7;
    126.             float  _Alpha0, _Alpha1, _Alpha2, _Alpha3, _Alpha4, _Alpha5, _Alpha6, _Alpha7;
    127.             float  _ColorTime0, _ColorTime1, _ColorTime2, _ColorTime3, _ColorTime4, _ColorTime5, _ColorTime6, _ColorTime7;
    128.             float  _AlphaTime0, _AlphaTime1, _AlphaTime2, _AlphaTime3, _AlphaTime4, _AlphaTime5, _AlphaTime6, _AlphaTime7;
    129.             int _Colors, _Alphas;
    130.  
    131.             float4 get_gradient(float2 texcoord)
    132.             {
    133.                 float4 cc[8] = { _Color0, _Color1, _Color2, _Color3, _Color4, _Color5, _Color6, _Color7 };
    134.                 float  aa[8] = { _Alpha0, _Alpha1, _Alpha2, _Alpha3, _Alpha4, _Alpha5, _Alpha6, _Alpha7 };
    135.                 float  ct[8] = { _ColorTime0, _ColorTime1, _ColorTime2, _ColorTime3, _ColorTime4, _ColorTime5, _ColorTime6, _ColorTime7 };
    136.                 float  at[8] = { _AlphaTime0, _AlphaTime1, _AlphaTime2, _AlphaTime3, _AlphaTime4, _AlphaTime5, _AlphaTime6, _AlphaTime7 };
    137.  
    138.                 float4 cv1 = cc[0], cv2 = cc[_Colors - 1];
    139.                 float  ct1 = ct[0], ct2 = ct[_Colors - 1];
    140.                 float  av1 = aa[0], av2 = aa[_Alphas - 1];
    141.                 float  at1 = at[0], at2 = at[_Alphas - 1];
    142.  
    143.                 float t = texcoord.x;
    144.  
    145.                 for (int i = 0; i < _Colors; i++)
    146.                 {
    147.                     if (ct[i] > t)
    148.                         break;
    149.  
    150.                     cv1 = cc[i];
    151.                     ct1 = ct[i];
    152.                 }
    153.  
    154.                 for (int j = 0; j < _Colors; j++)
    155.                 {
    156.                     if (ct[j] < t)
    157.                         continue;
    158.  
    159.                     cv2 = cc[j];
    160.                     ct2 = ct[j];
    161.                     break;
    162.                 }
    163.  
    164.                 for (int k = 0; k < _Alphas; k++)
    165.                 {
    166.                     if (at[k] > t)
    167.                         break;
    168.  
    169.                     av1 = aa[k];
    170.                     at1 = at[k];
    171.                 }
    172.  
    173.                 for (int l = 0; l < _Alphas; l++)
    174.                 {
    175.                     if (at[l] < t)
    176.                         continue;
    177.  
    178.                     av2 = aa[l];
    179.                     at2 = at[l];
    180.                     break;
    181.                 }
    182.  
    183.                 float  lerpA = (t - at1) / (at2 - at1);
    184.                 float  lerpC = (t - ct1) / (ct2 - ct1);
    185.                 float4 finalC = lerp(cv1, cv2, lerpC);
    186.                 float4 finalA = lerp(av1, av2, lerpA);
    187.                 finalC.a = finalA;
    188.  
    189.                 return finalC;
    190.             }
    191.  
    192.             v2f vert(appdata_t v)
    193.             {
    194.                 v2f OUT;
    195.                 UNITY_SETUP_INSTANCE_ID(v);
    196.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    197.                 OUT.worldPosition = v.vertex;
    198.                 OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
    199.  
    200.                 OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
    201.                 OUT.color = v.color * _Color;
    202.  
    203.                 return OUT;
    204.             }
    205.  
    206.             fixed4 frag(v2f IN) : SV_Target
    207.             {
    208.                 half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
    209.  
    210.                 #ifdef UNITY_UI_CLIP_RECT
    211.                 color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
    212.                 #endif
    213.  
    214.                 #ifdef UNITY_UI_ALPHACLIP
    215.                 clip (color.a - 0.001);
    216.                 #endif
    217.  
    218.                 float2 texcoord = (IN.texcoord - _MainTex_ST.zw) / _MainTex_ST.xy;
    219.                 float4 gradient = get_gradient(texcoord);
    220.                 return color * gradient;
    221.             }
    222.         ENDCG
    223.         }
    224.     }
    225.     CustomEditor "UIGradientShaderGUI"
    226. }
    227.  
    Enjoy and please share your improvements :).
     
    Last edited: Apr 8, 2019
    Zhelatin, JD_SP, Dams69 and 1 other person like this.
  2. LolBozo

    LolBozo

    Joined:
    Aug 31, 2019
    Posts:
    1
    I know this is way late, but this is the only gradient maker i can find that works anywhere, and i can get it to work from the editor, but how do i create gradients from code??
    Code (CSharp):
    1.         material = new Material(shader);
    2.  
    3.         material.SetColor("Color 0", color1);
    4.         material.SetFloat("Color Time 0", 0);
    5.         material.SetColor("Color 1", color2);
    6.         material.SetFloat("Color Time 1", 1);
    7.  
    I assumed that this would work
     
    Last edited: Oct 4, 2019
  3. aybe

    aybe

    Joined:
    May 24, 2015
    Posts:
    104
    A rough guess is that you have to use "_Color0" and so on ... shader variable name, not description.