GameTech/URP 渲染实战
源码 / shaders/Ch15/Gooch.glsl
shaders/Ch15/Gooch.glsl
// Gooch 冷暖着色:用“冷→暖”的色相变化代替“暗→亮”的明度变化来表达朝向,(GLSL 版,对应 Ch15/Gooch.shader)
// 暗部不再是死黑,形体在技术插图里依旧清楚。附带白色高光与背面外扩描边。
Shader "Cookbook/Ch15/Gooch"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        GLSLINCLUDE
        uniform vec4 _BaseColor, _CoolColor, _WarmColor, _OutlineColor;
        uniform float _Alpha, _Beta, _SpecPower, _SpecStrength, _ShadowCool;
        uniform float _OutlineWidth;
        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);
                vec3 V = GetWorldSpaceNormalizeViewDir(positionWS);
                NprLight L = GetNprLight(positionWS, N);

                // 1) 冷暖两端:纯冷/暖色 + 一部分物体本色
                vec3 kCool = _CoolColor.rgb + _Alpha * _BaseColor.rgb;
                vec3 kWarm = _WarmColor.rgb + _Beta  * _BaseColor.rgb;

                // 2) 用 (1 + N·L) / 2 在两端之间插值:背光面不是“没有光”,而是“偏冷”
                float t = (1.0 + L.ndotl) * 0.5;
                // 落在投影里的部分往冷端推一些(原始 Gooch 模型没有阴影,这是工程上的补充)
                t *= mix(1.0 - _ShadowCool, 1.0, L.shadow);
                vec3 col = mix(kCool, kWarm, t);

                // 3) 白色高光:Blinn-Phong,只在受光面出现
                vec3 H = normalize(L.direction + V);
                float spec = pow(saturate(dot(N, H)), _SpecPower) * _SpecStrength * L.shadow * step(0.0, L.ndotl);
                col += spec;

                col = MixFog(col, fogFactor);
                return vec4(col, 1.0);
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }

        // 背面外扩描边(第 14 章讲过的方法,这里只作为技术插图的黑色轮廓线)
        Pass
        {
            Name "Outline"
            Tags { "LightMode"="SRPDefaultUnlit" }
            Cull Front
            GLSLPROGRAM
            #ifdef VERTEX
            void main()
            {
                vec4 positionCS = TransformObjectToHClip(positionOS.xyz);
                vec3 normalCS = mat3(UNITY_MATRIX_VP) * TransformObjectToWorldNormal(normalOS);
                // 在裁剪空间沿法线外扩,乘 w 抵消透视除法,使线宽与距离无关
                vec2 offset = normalize(normalCS.xy) * _OutlineWidth * positionCS.w;
                offset.x *= _ScreenParams.y / _ScreenParams.x;   // 纠正宽高比
                positionCS.xy += offset;
                gl_Position = positionCS;
            }
            #endif
            #ifdef FRAGMENT
            void main() { fragColor = _OutlineColor; }
            #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
        }
    }
}