GameTech/URP 渲染实战
源码 / Ch04/C04_03_RingProgress.shader
Ch04/C04_03_RingProgress.shader
// 案例 4.3(上):圆环进度条 —— 极坐标判断“走到哪了”,SDF 画圆头。
Shader "Cookbook/Ch04/RingProgress"
{
    Properties
    {
        _Progress ("Progress", Range(0, 1)) = 0.65
        _Radius ("Radius", Range(0.1, 0.9)) = 0.62
        _Thickness ("Thickness", Range(0.01, 0.5)) = 0.16
        _ColorStart ("Color Start", Color) = (0.12, 0.62, 0.86, 1)
        _ColorEnd ("Color End", Color) = (0.91, 0.45, 0.23, 1)
        _TrackColor ("Track Color", Color) = (0.22, 0.26, 0.30, 1)
        _BgColor ("Background", Color) = (0.08, 0.10, 0.12, 1)
        [HDR] _GlowColor ("Glow", Color) = (0.6, 0.35, 0.15, 1)
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        Pass
        {
            Name "Unlit"
            Tags { "LightMode"="UniversalForward" }

            HLSLPROGRAM
            #pragma vertex ProceduralVert
            #pragma fragment frag
            #include "Assets/Cookbook/Ch04/ProceduralCommon.hlsl"

            CBUFFER_START(UnityPerMaterial)
                float _Progress, _Radius, _Thickness;
                half4 _ColorStart, _ColorEnd, _TrackColor, _BgColor, _GlowColor;
            CBUFFER_END

            half4 frag (Varyings input) : SV_Target
            {
                float2 p = input.uv * 2.0 - 1.0;                 // [-1,1],中心为原点
                float r = length(p);
                // 从 12 点方向开始、顺时针增加的角度,归一化到 [0,1)
                float a01 = frac(atan2(p.x, p.y) / TWO_PI + 1.0);
                float hw = _Thickness * 0.5;

                float ring = abs(r - _Radius) - hw;              // 整圈环带的 SDF
                // 已走过的部分:角度在进度内就用环带距离,否则用到两个“圆头”的距离
                float endAngle = _Progress * TWO_PI;
                float2 capStart = float2(0.0, _Radius);
                float2 capEnd   = _Radius * float2(sin(endAngle), cos(endAngle));
                float caps = min(length(p - capStart), length(p - capEnd)) - hw;
                float arc = (a01 <= _Progress) ? ring : caps;
                if (_Progress <= 0.0) arc = 1.0;                  // 进度为 0 时什么都不画

                half3 col = _BgColor.rgb;
                col = lerp(col, _TrackColor.rgb, FillAA(ring));  // 底部轨道
                // 外发光:距离越远越暗的指数衰减
                col += _GlowColor.rgb * exp(-max(arc, 0.0) * 30.0) * 0.6;
                // 沿弧长渐变;圆头部分按离哪个头近取首/尾颜色
                float t = (a01 <= _Progress) ? a01 / max(_Progress, 1e-4)
                                             : (length(p - capStart) < length(p - capEnd) ? 0.0 : 1.0);
                half3 fillCol = lerp(_ColorStart.rgb, _ColorEnd.rgb, t);
                col = lerp(col, fillCol, FillAA(arc));
                return half4(col, 1);
            }
            ENDHLSL
        }
    }
}