GameTech/URP 渲染实战
源码 / shaders/Ch24/SGDissolveEquivalent.glsl
shaders/Ch24/SGDissolveEquivalent.glsl
// 第 24 章:与“Lit Graph 溶解”等价的手写 Shader(GLSL 版)。
// Lit Graph 的 Master Stack 输出 Base Color / Metallic / Smoothness / Emission / Alpha / Alpha Clip Threshold,
// 生成代码最终把它们填进 SurfaceData 再调用 UniversalFragmentPBR —— 这里照做一遍。
Shader "Cookbook/Ch24/SGDissolveEquivalent"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="AlphaTest" }

        GLSLINCLUDE
        #include "Ch24/StylizedFunctions.glsl"
        uniform vec4  _BaseColor;
        uniform float _Metallic;
        uniform float _Smoothness;
        uniform vec4  _NoiseMap_ST;
        uniform float _Progress;
        uniform float _EdgeWidth;
        uniform vec4  _EdgeColor;
        uniform sampler2D _NoiseMap;

        // 图里“Sample Texture 2D → Dissolve”这一段,所有 Pass 共用
        void DissolveGraph(vec2 uv, out float alpha, out float edge)
        {
            float noise = texture(_NoiseMap, TransformTex(uv, _NoiseMap_ST)).r;
            Dissolve_float(noise, _Progress, _EdgeWidth, alpha, edge);
        }
        ENDGLSL

        Pass
        {
            Name "Universal Forward"
            Tags { "LightMode"="UniversalForward" }
            GLSLPROGRAM
            VARYING vec2 uv;
            VARYING vec3 positionWS;
            VARYING vec3 normalWS;

            #ifdef VERTEX
            void main()
            {
                VertexPositionInputs p = GetVertexPositionInputs(positionOS.xyz);
                gl_Position = p.positionCS; positionWS = p.positionWS;
                normalWS = TransformObjectToWorldNormal(normalOS);
                uv = texcoord0.xy;
            }
            #endif

            #ifdef FRAGMENT
            vec4 frag()
            {
                float alpha, edge;
                DissolveGraph(uv, alpha, edge);
                if (alpha - 0.5 < 0.0) discard;              // Alpha Clip Threshold = 0.5

                SurfaceData surface = InitSurfaceData();     // ← Master Stack 的各个 Block
                surface.albedo     = _BaseColor.rgb * (1.0 - edge);
                surface.metallic   = _Metallic;
                surface.smoothness = _Smoothness;
                surface.occlusion  = 1.0;
                surface.emission   = edge * _EdgeColor.rgb;
                surface.alpha      = 1.0;
                surface.normalTS   = vec3(0, 0, 1);

                InputData inputData = InitInputData();
                inputData.positionWS = positionWS;
                inputData.normalWS = normalize(normalWS);
                inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(positionWS);
                inputData.shadowCoord = TransformWorldToShadowCoord(positionWS);
                inputData.bakedGI = SampleSH(inputData.normalWS);
                inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(gl_FragCoord);
                inputData.shadowMask = vec4(1, 1, 1, 1);
                return UniversalFragmentPBR(inputData, surface);
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }

        Pass
        {
            // Shader Graph 会自动把 Alpha Clip 带进 ShadowCaster / DepthOnly;手写时最容易忘
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On ZTest LEqual ColorMask 0
            GLSLPROGRAM
            #include "Ch23/Ch23Common.glsl"
            VARYING vec2 uv;
            #ifdef VERTEX
            void main()
            {
                gl_Position = Ch23ShadowCasterVert();
                uv = texcoord0.xy;
            }
            #endif
            #ifdef FRAGMENT
            void main()
            {
                float alpha, edge;
                DissolveGraph(uv, alpha, edge);
                if (alpha - 0.5 < 0.0) discard;
                fragColor = vec4(0.0);
            }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On ColorMask R
            GLSLPROGRAM
            VARYING vec2 uv;
            #ifdef VERTEX
            void main() { gl_Position = TransformObjectToHClip(positionOS.xyz); uv = texcoord0.xy; }
            #endif
            #ifdef FRAGMENT
            void main()
            {
                float alpha, edge;
                DissolveGraph(uv, alpha, edge);
                if (alpha - 0.5 < 0.0) discard;
                fragColor = vec4(gl_FragCoord.z);
            }
            #endif
            ENDGLSL
        }
    }
}