UI动效 05

  1. 1. 按钮UI动效——水波纹涟漪点击效果

按钮UI动效——水波纹涟漪点击效果


  • 效果图:
  • 按钮Mask贴图:

    可以自己画

  • 源代码:
  • Shader(不使用SDF):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    Shader "Unlit/BtnClickWaveShader"
    {
    Properties
    {
    _MainTex ("Texture", 2D) = "white" {}
    _ColorLeft ("ColorLeft", Color) = (0,1,0,1)
    _ColorRight ("ColorRight", Color) = (0,0,1,1)
    _Radius ("Radius", Float) = 1
    _RadiusThickness ("RadiusThickness", Float) = 1
    _WaveAlpha ("WaveAlpha", Range(0, 1)) = 0.5
    [HDR] _WaveColor ("WaveColor", Color) = (1,1,1,1)
    [hideInInspector] _CircleScaleOffset ("CircleScaleOffset", Float) = 1 // Width / Height
    [hideInInspector] _MouseUVPos ("MouseUVPos", Vector) = (0,0,0,0)
    }
    SubShader
    {
    Tags { "RenderType"="Transparent" "Queue"="Transparent"}
    Blend SrcAlpha OneMinusSrcAlpha

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;
    float4 _ColorLeft;
    float4 _ColorRight;


    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    fixed4 shape = tex2D(_MainTex, i.uv);
    fixed4 col = fixed4(lerp(_ColorLeft, _ColorRight, i.uv.x).rgb, shape.a);
    return col;
    }
    ENDCG
    }
    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;
    float4 _ColorLeft;
    float4 _ColorRight;
    float _Radius;
    float _RadiusThickness;
    float _CircleScaleOffset;
    float _WaveAlpha;
    float4 _WaveColor;
    float4 _MouseUVPos;

    fixed4 PixelColor(float2 uv)
    {
    // 将uv原点移到中心
    uv -= _MouseUVPos.xy;
    uv = uv * 2 - 1;
    // 离uv坐标原点的距离,排除屏幕长宽比、图片长宽比的影响
    float2 dv = float2(uv.x, uv.y)* float2(_ScreenParams.x / _ScreenParams.y * _CircleScaleOffset, 1);
    float d = sqrt(pow(dv.x, 2) + pow(dv.y, 2));
    // 用小圆减大圆 得到圆环
    fixed3 c = smoothstep(_Radius-_RadiusThickness, _Radius, d) - smoothstep(_Radius, _Radius+_RadiusThickness, d);

    return fixed4(c * _WaveColor.rgb, saturate(c.g)); // -0.5
    }

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    fixed4 shape = tex2D(_MainTex, i.uv);
    fixed4 wave = PixelColor(i.uv);
    wave.rgb *= _WaveColor.rgb;
    wave.a *= shape.a * _WaveAlpha;
    return wave;
    }
    ENDCG
    }
    }
    }

  • Shader(使用SDF):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    Shader "Unlit/BtnClickWaveSDFShader"
    {
    Properties
    {
    _MainTex ("Texture", 2D) = "white" {}
    _ColorLeft ("ColorLeft", Color) = (0,1,0,1)
    _ColorRight ("ColorRight", Color) = (0,0,1,1)
    [hideInInspector] _CircleScaleOffset ("CircleScaleOffset", Float) = 1 // Width / Height
    [hideInInspector] _CirclePosOffset ("CirclePosOffset", Vector) = (0,0,0,0)
    _Radius ("Radius", Float) = 1.5
    _RadiusThickness ("RadiusThickness", Float) = 0.2
    [HDR] _WaveColor ("WaveColor", Color) = (1,1,1,1)
    }
    SubShader
    {
    Tags { "RenderType"="Transparent" "Queue"="Transparent"}
    Blend SrcAlpha OneMinusSrcAlpha

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;
    float4 _ColorLeft;
    float4 _ColorRight;

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    fixed4 shape = tex2D(_MainTex, i.uv);
    fixed4 col = fixed4(lerp(_ColorLeft, _ColorRight, i.uv.x).rgb, shape.a);
    return col;
    }
    ENDCG
    }
    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _CircleScaleOffset;
    float _Radius;
    float4 _CirclePosOffset;
    float _RadiusThickness;
    float4 _WaveColor;

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    return o;
    }

    float sdCircle(float2 p, float r)
    {
    return length(p) - r;
    }
    float opAnnular(float sdf, float r)
    {
    return abs(sdf) - r;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    fixed4 shape = tex2D(_MainTex, i.uv);
    // 全象限
    i.uv -= _CirclePosOffset.xy;
    i.uv.y = 1.0 - i.uv.y;
    i.uv = i.uv * 2 - 1;
    // 消除屏幕拉伸影响
    float w = _ScreenParams.x;
    float h = _ScreenParams.y;
    half co = w/h * _CircleScaleOffset;
    i.uv = float2(i.uv.x * co, i.uv.y);

    float step = 1.0 / w;
    fixed4 circle = smoothstep(step, -step, opAnnular(sdCircle(i.uv, _Radius) , _RadiusThickness));

    fixed4 col = fixed4(circle.rgb, shape.a);
    col.rgb = col.rgb * _WaveColor.rgb;
    col.a *= col.r;
    col.a = _WaveColor.a * col.a;

    return col;
    }
    ENDCG
    }
    }
    }

  • C#(两种shader共用):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    using UnityEngine;
    using UnityEngine.UI;
    using DG.Tweening;

    public class BtnClickWaveControl : MonoBehaviour
    {
    private Material material;
    private Button btn;
    private Sequence sequence;
    [SerializeField] private float waveDuration = 2f;
    private Vector2 mouseUVPos;
    // SDF
    [SerializeField] private bool useSDF = false;
    private Vector4 tmp_color;
    private Vector4 targetColor;
    void Start()
    {
    material = GetComponent<Image>().material = new Material(GetComponent<Image>().material);
    btn = GetComponent<Button>();
    RectTransform rect = GetComponent<RectTransform>();

    material.SetFloat("_CircleScaleOffset", rect.sizeDelta.x / rect.sizeDelta.y);
    material.SetFloat("_Radius", -material.GetFloat("_RadiusThickness"));
    if (useSDF)
    {
    tmp_color = material.GetColor("_WaveColor");
    targetColor = new Vector4(tmp_color.x, tmp_color.y, tmp_color.z, 0);
    }

    btn.onClick.AddListener(() =>
    {
    Vector2 uipos = Vector3.one;
    RectTransformUtility.ScreenPointToLocalPointInRectangle(transform.parent as RectTransform, Input.mousePosition, Camera.main, out uipos);
    mouseUVPos = (uipos - (Vector2)rect.localPosition) / rect.sizeDelta;
    if (!useSDF)
    {
    material.SetVector("_MouseUVPos", mouseUVPos);

    sequence?.Kill();
    sequence = DOTween.Sequence().SetUpdate(true).SetId(transform)
    .AppendCallback(() =>
    {
    material.SetFloat("_Radius", -material.GetFloat("_RadiusThickness"));
    })
    .Append(material.DOFloat(10f, "_Radius", waveDuration));
    }
    else
    {
    material.SetVector("_CirclePosOffset", mouseUVPos);

    sequence?.Kill();
    sequence = DOTween.Sequence().SetUpdate(true).SetId(transform)
    .AppendCallback(() =>
    {
    material.SetFloat("_Radius", -material.GetFloat("_RadiusThickness"));
    material.SetColor("_WaveColor", tmp_color);
    })
    .Append(material.DOFloat(6f, "_Radius", waveDuration))
    .Join(material.DOColor(targetColor, "_WaveColor", waveDuration));
    }

    });
    }

    private void OnDestroy()
    {
    DOTween.Kill(transform);
    }
    }