GameTech/URP 渲染实战
源码 / shaders/Ch04/C04_03_RingProgress.glsl
shaders/Ch04/C04_03_RingProgress.glsl
// 案例 4.3(上):圆环进度条 —— 极坐标判断“走到哪了”,SDF 画圆头。(GLSL 版)
Shader "Cookbook/Ch04/RingProgress"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }

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

            GLSLPROGRAM
            #include "Ch04/ProceduralCommon.glsl"

            uniform float _Progress, _Radius, _Thickness;
            uniform vec4  _ColorStart, _ColorEnd, _TrackColor, _BgColor, _GlowColor;

            #ifdef FRAGMENT
            void main()
            {
                vec2 p = uv * 2.0 - 1.0;                         // [-1,1],中心为原点
                float r = length(p);
                // 从 12 点方向开始、顺时针增加的角度,归一化到 [0,1)
                float a01 = fract(atan(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;
                vec2 capStart = vec2(0.0, _Radius);
                vec2 capEnd   = _Radius * vec2(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 时什么都不画

                vec3 col = _BgColor.rgb;
                col = mix(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);
                vec3 fillCol = mix(_ColorStart.rgb, _ColorEnd.rgb, t);
                col = mix(col, fillCol, FillAA(arc));
                fragColor = vec4(col, 1.0);
            }
            #endif
            ENDGLSL
        }
    }
}