GameTech/URP 渲染实战
源码 / shaders/Ch04/C04_06_Voronoi.glsl
shaders/Ch04/C04_06_Voronoi.glsl
// 案例 4.6:Voronoi 细胞 —— F1 距离、F2-F1 边界、按格子 id 上色。(GLSL 版)
Shader "Cookbook/Ch04/Voronoi"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }

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

            GLSLPROGRAM
            #include "Ch04/ProceduralCommon.glsl"

            uniform float _Mode, _Scale, _Phase, _Speed, _EdgeWidth;
            uniform vec4  _ColorA, _ColorB, _EdgeColor;

            #ifdef FRAGMENT
            void main()
            {
                vec2 p = uv * _Scale;
                float f1, f2; vec2 cell;
                Voronoi(p, _Phase + _Time.y * _Speed, f1, f2, cell);

                vec3 col;
                if (_Mode < 0.5)
                {
                    // F1:到最近特征点的距离 → 一个个“圆锥”,加等高线更容易看出形状
                    col = mix(_ColorA.rgb, _ColorB.rgb, saturate(f1 * 1.4));
                    col *= 0.85 + 0.15 * step(0.5, fract(f1 * 8.0));
                    col = mix(col, _EdgeColor.rgb, 1.0 - smoothstep(0.03, 0.05, f1));   // 特征点
                }
                else if (_Mode < 1.5)
                {
                    // F2 - F1:两个最近点距离相等的地方就是细胞边界,那里差值趋于 0
                    float e = f2 - f1;
                    col = mix(_EdgeColor.rgb, _ColorB.rgb, smoothstep(0.0, _EdgeWidth * 2.0, e));
                }
                else
                {
                    // 用最近格子的编号再哈希一次,每个细胞一个固定颜色
                    float h = Hash21(cell + 31.7);
                    col = mix(_ColorA.rgb, _ColorB.rgb, h);
                    // 用到边界的真实距离做明暗和描边:中心亮、边缘暗,像鹅卵石
                    float border = VoronoiBorder(p, _Phase + _Time.y * _Speed);
                    col *= mix(0.7, 1.1, saturate(border * 2.5));
                    float aa = fwidth(border);
                    col = mix(_EdgeColor.rgb, col, smoothstep(_EdgeWidth * 0.5 - aa, _EdgeWidth * 0.5 + aa, border));
                }
                fragColor = vec4(col, 1.0);
            }
            #endif
            ENDGLSL
        }
    }
}