GameTech/URP 渲染实战
源码 / shaders/Ch20/HeightBlend.glsl
shaders/Ch20/HeightBlend.glsl
// 案例 20.5:线性混合 vs 高度混合——砖地上长出的草先填满砖缝(GLSL 版,对应 Ch20/HeightBlend.shader)
Shader "Cookbook/Ch20/HeightBlend"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        GLSLINCLUDE
        uniform vec4 _MapA_ST;
        uniform float _TilingB;
        uniform float _MaskContrast, _MaskOffset, _UseHeight, _BlendDepth;
        ENDGLSL

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode"="UniversalForwardOnly" }   // 自定义表面混合,没有 GBuffer Pass:Deferred 下也走前向
            GLSLPROGRAM
            #pragma multi_compile_fog
            #pragma multi_compile_instancing

            #include "Ch20/TerrainCommon.glsl"

            uniform sampler2D _MapA;
            uniform sampler2D _HeightA;
            uniform sampler2D _NormalA;
            uniform sampler2D _MapB;
            uniform sampler2D _NoiseTex;

            VARYING vec3 positionWS;
            VARYING vec3 normalWS;
            VARYING vec4 tangentWS;
            VARYING vec2 uv;
            VARYING float fogFactor;

            #ifdef VERTEX
            void main()
            {
                VertexPositionInputs p = GetVertexPositionInputs(positionOS.xyz);
                VertexNormalInputs nI = GetVertexNormalInputs(normalOS, tangentOS);
                gl_Position = p.positionCS;
                positionWS = p.positionWS;
                normalWS = nI.normalWS;
                tangentWS = vec4(nI.tangentWS, tangentOS.w * GetOddNegativeScale());
                uv = texcoord0.xy;
                fogFactor = ComputeFogFactor(p.positionCS.z);
            }
            #endif

            #ifdef FRAGMENT
            vec4 frag()
            {
                vec2 uvA = TransformTex(uv, _MapA_ST);
                vec2 uvB = uv * _TilingB;
                vec3 albedoA = texture(_MapA, uvA).rgb;
                float heightA = texture(_HeightA, uvA).r;
                vec3 normalA = UnpackNormalmapRGorAG(texture(_NormalA, uvA), 1.0);   // = URP 桌面平台的 UnpackNormal
                vec4 layerB  = texture(_MapB, uvB);

                // 遮罩:从左到右的渐变 + 噪声,模拟“刷”出来的过渡区
                float noise = texture(_NoiseTex, uv * 1.5).r - 0.5;
                float mask = saturate((uv.x - 0.5 + _MaskOffset + noise * 0.35) * _MaskContrast + 0.5);

                // 线性混合 vs 高度混合
                float tLinear = mask;
                float tHeight = HeightBlendWeight(heightA, layerB.a, mask, _BlendDepth);
                float t = mix(tLinear, tHeight, _UseHeight);

                vec3 albedo = mix(albedoA, layerB.rgb, t);
                vec3 normalTS = normalize(mix(normalA, vec3(0, 0, 1), t));
                float sgn = tangentWS.w;
                vec3 bitangent = sgn * cross(normalWS, tangentWS.xyz);
                // HLSL 的 half3x3(T, B, N) 按行构造;GLSL 的 mat3(T, B, N) 列就是 T/B/N,TransformTangentToWorld 已按此处理
                vec3 nWS = TransformTangentToWorld(normalTS, mat3(tangentWS.xyz, bitangent, normalWS));
                float occlusion = mix(mix(0.6, 1.0, heightA), 1.0, t);   // 砖缝顺手压暗一点
                return Ch20ShadePBR(positionWS, nWS, gl_FragCoord, albedo, 0.0, mix(0.3, 0.12, t), occlusion, fogFactor);
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On ZTest LEqual ColorMask 0
            GLSLPROGRAM
            #pragma multi_compile_instancing
            #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
            #define CH20_SHADOW_PASS
            #include "Ch20/ShadowDepthPasses.glsl"
            ENDGLSL
        }
        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On ColorMask R
            GLSLPROGRAM
            #pragma multi_compile_instancing
            #define CH20_DEPTH_PASS
            #include "Ch20/ShadowDepthPasses.glsl"
            ENDGLSL
        }
    }
}