GameTech/URP 渲染实战
源码 / shaders/Ch03/C03_09_ScrollMigrated.glsl
shaders/Ch03/C03_09_ScrollMigrated.glsl
// 案例 3.9:把一个 Built-in 管线的“滚动贴图 Unlit”迁移到 URP。
// 对照正文里的 Built-in 原版逐行看:每一处改动都对应对照表里的一行。
Shader "Cookbook/Ch03/ScrollMigrated"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        GLSLINCLUDE
        // CBUFFER_START(UnityPerMaterial)
        uniform vec4 _BaseMap_ST;
        uniform vec4 _BaseColor;
        uniform vec4 _ScrollSpeed;
        uniform vec4 _ScrollOffset;
        // CBUFFER_END

        uniform sampler2D _BaseMap;
        ENDGLSL

        Pass
        {
            Name "Unlit"
            // Unlit 用 UniversalForwardOnly:切到 Deferred 渲染路径也不会消失(见正文 3.4 节)
            Tags { "LightMode"="UniversalForwardOnly" }

            GLSLPROGRAM                                  // CGPROGRAM → HLSLPROGRAM(网页版:GLSLPROGRAM)
            #pragma multi_compile_fog

            // appdata → Attributes(网页版:固定名字的顶点输入 positionOS / texcoord0 / color)
            // v2f → Varyings(网页版:逐个 VARYING)
            VARYING vec2 uv;
            VARYING vec4 vColor;                         // fixed4 → half4(URP 不再有 fixed)
            VARYING float fogFactor;                     // UNITY_FOG_COORDS(1) → 自己声明

            #ifdef VERTEX
            void main()
            {
                // UnityObjectToClipPos → TransformObjectToHClip
                gl_Position = TransformObjectToHClip(positionOS.xyz);
                // _Time.y 的含义与 Built-in 相同:游戏开始后的秒数
                vec2 scroll = _ScrollSpeed.xy * _Time.y + _ScrollOffset.xy;
                uv = TransformTex(texcoord0.xy, _BaseMap_ST) + scroll;
                vColor = color;
                // UNITY_TRANSFER_FOG(o, o.pos) → ComputeFogFactor
                fogFactor = ComputeFogFactor(gl_Position.z);
            }
            #endif

            #ifdef FRAGMENT
            void main()
            {
                // tex2D(_MainTex, uv) → SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv)(网页版:texture)
                vec4 col = texture(_BaseMap, uv) * _BaseColor * vColor;
                // UNITY_APPLY_FOG(i.fogCoord, col) → MixFog
                col.rgb = MixFog(col.rgb, fogFactor);
                fragColor = vec4(col.rgb, 1);
            }
            #endif
            ENDGLSL
        }

        // Built-in 版本靠 Fallback 借来阴影 Pass;URP 里自己写一个最简的 ShadowCaster
        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On
            ColorMask 0

            GLSLPROGRAM
            // _CASTING_PUNCTUAL_LIGHT_SHADOW 在网页版是 uniform _CastingPunctualLightShadow;ApplyShadowBias 等由 Lighting.glsl 提供
            #ifdef VERTEX
            void main()
            {
                vec3 positionWS = TransformObjectToWorld(positionOS.xyz);
                vec3 normalWS   = TransformObjectToWorldNormal(normalOS);
                vec3 lightDirectionWS = _CastingPunctualLightShadow > 0.5
                    ? normalize(_LightPosition - positionWS)
                    : _LightDirection;
                gl_Position = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
            #if UNITY_REVERSED_Z
                gl_Position.z = min(gl_Position.z, UNITY_NEAR_CLIP_VALUE);
            #else
                gl_Position.z = max(gl_Position.z, UNITY_NEAR_CLIP_VALUE);
            #endif
            }
            #endif

            #ifdef FRAGMENT
            void main() { fragColor = vec4(0.0); }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On
            ColorMask R

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

            #ifdef FRAGMENT
            void main() { fragColor = vec4(gl_FragCoord.z); }
            #endif
            ENDGLSL
        }
    }
}