GameTech/URP 渲染实战
源码 / shaders/Ch15/BaryWireframe.glsl
shaders/Ch15/BaryWireframe.glsl
// 重心坐标线框:网格的顶点色里预先烘焙了重心坐标 (1,0,0)/(0,1,0)/(0,0,1),(GLSL 版,对应 Ch15/BaryWireframe.shader)
// 光栅化插值后,某个分量接近 0 就说明像素靠近对应的边。fwidth 让线宽以“像素”为单位恒定。
Shader "Cookbook/Ch15/BaryWireframe"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        GLSLINCLUDE
        uniform vec4 _BaseColor, _WireColor;
        uniform float _WireWidth;

        #ifdef FRAGMENT
        // 返回 0..1 的“线框覆盖度”。bary 来自顶点色插值。
        float WireFactor(vec3 bary, float widthPixels)
        {
            vec3 d = fwidth(bary);                      // 每个分量在一个像素内的变化量
            vec3 a = smoothstep(d * (widthPixels - 0.5), d * (widthPixels + 0.5), bary);
            return 1.0 - min(a.x, min(a.y, a.z));       // 任一分量接近 0 → 在边上
        }
        #endif
        ENDGLSL

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode"="UniversalForwardOnly" }
            GLSLPROGRAM
            #define NPR_VARYINGS
            #include "Ch15/NPRCommon.glsl"

            #ifdef VERTEX
            void main() { NprVert(); }
            #endif

            #ifdef FRAGMENT
            vec4 frag()
            {
                vec3 N = normalize(normalWS);
                NprLight L = GetNprLight(positionWS, N);
                vec3 fill = _BaseColor.rgb * (saturate(L.ndotl) * L.shadow * L.color + SampleSH(N));
                float w = WireFactor(vertexColor.rgb, _WireWidth);
                return vec4(mix(fill, _WireColor.rgb, w), 1.0);
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On ZTest LEqual ColorMask 0
            GLSLPROGRAM
            #define NPR_SHADOW_PASS
            #include "Ch15/NPRCommon.glsl"
            ENDGLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On ColorMask R
            GLSLPROGRAM
            #define NPR_DEPTH_PASS
            #include "Ch15/NPRCommon.glsl"
            ENDGLSL
        }
    }
}