GameTech/URP 渲染实战
源码 / shaders/Ch05/WrapLighting.glsl
shaders/Ch05/WrapLighting.glsl
// 案例 5.3 Wrap Lighting:让光“绕过”明暗交界线,可选能量守恒和交界线染色(GLSL 版)
Shader "Cookbook/Ch05/WrapLighting"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }

        GLSLINCLUDE
        uniform vec4  _BaseColor;
        uniform float _Wrap;
        uniform vec4  _TerminatorTint;
        uniform float _AmbientStrength;
        ENDGLSL

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

            GLSLPROGRAM
            #pragma shader_feature_local_fragment _WRAP_ENERGY_CONSERVING
            VARYING vec3 normalWS;

            #ifdef VERTEX
            void main()
            {
                gl_Position = TransformObjectToHClip(positionOS.xyz);
                normalWS = TransformObjectToWorldNormal(normalOS);
            }
            #endif

            #ifdef FRAGMENT
            float WrapDiffuse(float NdotL, float w)
            {
            #if defined(_WRAP_ENERGY_CONSERVING)
                // 分母 (1+w)^2:被照亮的范围变大了,峰值相应压低,总能量与 Lambert 相同
                return saturate((NdotL + w) / ((1.0 + w) * (1.0 + w)));
            #else
                // 经典写法:w = 0 时退化为 Lambert,w = 1 时等价于未平方的 Half-Lambert
                return saturate((NdotL + w) / (1.0 + w));
            #endif
            }

            void main()
            {
                vec3 N = normalize(normalWS);
                Light mainLight = GetMainLight();
                vec3 radiance = mainLight.color * mainLight.distanceAttenuation;

                float NdotL = dot(N, mainLight.direction);
                float wrap = WrapDiffuse(NdotL, _Wrap);

                // 交界线染色:只在“Wrap 有、Lambert 没有”的那一圈加颜色,模拟光在皮下散射后带出的红色
                float scatter = saturate(wrap - saturate(NdotL));
                vec3 diffuse = _BaseColor.rgb * radiance * wrap
                             + _TerminatorTint.rgb * radiance * scatter;

                vec3 ambient = _BaseColor.rgb * SampleSH(N) * _AmbientStrength;
                fragColor = vec4(diffuse + ambient, 1.0);
            }
            #endif
            ENDGLSL
        }

        // ---- 投影与深度:本章先照抄,原理见第 6 章 ----
        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On
            ZTest LEqual
            ColorMask 0
            GLSLPROGRAM
            #define SHADOW_PASS
            #include "Ch05/Ch05ShadowDepth.glsl"
            ENDGLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On
            ColorMask R
            GLSLPROGRAM
            #define DEPTH_PASS
            #include "Ch05/Ch05ShadowDepth.glsl"
            ENDGLSL
        }
    }
}