GameTech/URP 渲染实战
源码 / shaders/Ch10/MinimalLit.glsl
shaders/Ch10/MinimalLit.glsl
// 第 10 章:最小 Lit。(GLSL 版,对应 Ch10/MinimalLit.shader)
// 自己准备 SurfaceData 和 InputData,然后直接调用 URP 的 UniversalFragmentPBR —— 光照结果与 URP Lit 一致,
// 但代码量只有 Lit 的一小部分,便于看清“喂给 PBR 的到底是什么”。
// 省略了:光照贴图、视差、细节贴图、Mask Map、透明、清漆、Decal、Light Cookie、Rendering Layers、Debug Display。
Shader "Cookbook/Ch10/MinimalLit"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "UniversalMaterialType"="Lit" "Queue"="Geometry" }

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

            GLSLPROGRAM
            // 材质关键字:有法线贴图才开(脚本创建材质时要自己 EnableKeyword)
            #pragma shader_feature_local _NORMALMAP
            // 管线关键字(主光阴影、附加光、软阴影、SSAO、雾):网页版引擎始终提供,不用声明;
            // 反射探针混合/盒体投影、Forward+、GPU Instancing 网页版没有

            #include "Ch10/MinimalLitInput.glsl"

            VARYING vec2 uv;
            VARYING vec3 positionWS;
            VARYING vec3 normalWS;
            VARYING vec4 tangentWS;   // w = 副切线符号
            VARYING float fogFactor;

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

            #ifdef FRAGMENT
            SurfaceData BuildSurfaceData(vec2 uv)
            {
                SurfaceData s = InitSurfaceData();
                vec4 albedoAlpha = SampleAlbedoAlpha(uv);
                s.albedo     = albedoAlpha.rgb * _BaseColor.rgb;
                s.alpha      = 1.0;                      // 不透明
                s.metallic   = _Metallic;                // 金属度工作流:specular 留 0
                s.specular   = vec3(0.0);
                s.smoothness = _Smoothness;
                s.normalTS   = SampleNormal(uv, _BumpScale);
                s.occlusion  = 1.0;
                s.emission   = _EmissionColor.rgb;
                s.clearCoatMask = 0.0;
                s.clearCoatSmoothness = 0.0;
                return s;
            }

            InputData BuildInputData(vec3 normalTS)
            {
                InputData d = InitInputData();
                d.positionWS = positionWS;
                d.positionCS = gl_FragCoord;

            #if defined(_NORMALMAP)
                vec3 bitangent = tangentWS.w * cross(normalWS, tangentWS.xyz);
                d.tangentToWorld = mat3(tangentWS.xyz, bitangent, normalWS);   // GLSL 的 mat3 按列构造:列 = T、B、N
                d.normalWS = TransformTangentToWorld(normalTS, d.tangentToWorld);
            #else
                d.normalWS = normalWS;
            #endif
                d.normalWS = NormalizeNormalPerPixel(d.normalWS);
                d.viewDirectionWS = GetWorldSpaceNormalizeViewDir(positionWS);

                d.shadowCoord = TransformWorldToShadowCoord(positionWS);   // 逐像素算级联,省一个插值器
                d.fogCoord = fogFactor;
                d.vertexLighting = vec3(0.0);
                d.bakedGI = SampleSH(d.normalWS);                          // 无光照贴图:逐像素 SH
                d.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(gl_FragCoord);
                d.shadowMask = vec4(1.0);
                return d;
            }

            void main()
            {
                SurfaceData surfaceData = BuildSurfaceData(uv);
                InputData inputData = BuildInputData(surfaceData.normalTS);

                vec4 color = UniversalFragmentPBR(inputData, surfaceData);
                color.rgb = MixFog(color.rgb, inputData.fogCoord);
                fragColor = color;
            }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On ZTest LEqual ColorMask 0

            GLSLPROGRAM
            // 先 include 自己的输入(uniform 与 ForwardLit 相同),再复用 URP 的阴影投射 Pass(ShadowCasterPass.hlsl 的 GLSL 写法)
            #include "Ch10/MinimalLitInput.glsl"
            VARYING vec2 uv;
            #ifdef VERTEX
            void main()   // ShadowPassVertex
            {
                uv = TransformTex(texcoord0.xy, _BaseMap_ST);
                gl_Position = GetShadowPositionHClip(positionOS.xyz, normalOS);
            }
            #endif
            #ifdef FRAGMENT
            void main()   // ShadowPassFragment
            {
                Alpha(SampleAlbedoAlpha(uv).a, _BaseColor, _Cutoff);
                fragColor = vec4(0.0);
            }
            #endif
            ENDGLSL
        }

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

            GLSLPROGRAM
            #include "Ch10/MinimalLitInput.glsl"
            VARYING vec2 uv;
            #ifdef VERTEX
            void main()   // DepthOnlyVertex
            {
                uv = TransformTex(texcoord0.xy, _BaseMap_ST);
                gl_Position = TransformObjectToHClip(positionOS.xyz);
            }
            #endif
            #ifdef FRAGMENT
            void main()   // DepthOnlyFragment
            {
                Alpha(SampleAlbedoAlpha(uv).a, _BaseColor, _Cutoff);
                fragColor = vec4(gl_FragCoord.z);
            }
            #endif
            ENDGLSL
        }

        Pass
        {
            // 开了 SSAO(Depth Normals 模式)或其他需要 _CameraNormalsTexture 的功能时会用到
            Name "DepthNormals"
            Tags { "LightMode"="DepthNormals" }
            ZWrite On

            GLSLPROGRAM
            #pragma shader_feature_local _NORMALMAP
            #include "Ch10/MinimalLitInput.glsl"
            VARYING vec2 uv;
            VARYING vec3 normalWS;
            VARYING vec4 tangentWS;
            #ifdef VERTEX
            void main()   // DepthNormalsVertex(LitDepthNormalsPass.hlsl)
            {
                uv = TransformTex(texcoord0.xy, _BaseMap_ST);
                VertexNormalInputs n = GetVertexNormalInputs(normalOS, tangentOS);
                normalWS = n.normalWS;
                tangentWS = vec4(n.tangentWS, tangentOS.w * GetOddNegativeScale());
                gl_Position = TransformObjectToHClip(positionOS.xyz);
            }
            #endif
            #ifdef FRAGMENT
            void main()   // DepthNormalsFragment
            {
                Alpha(SampleAlbedoAlpha(uv).a, _BaseColor, _Cutoff);
            #ifdef _NORMALMAP
                vec3 nTS = SampleNormal(uv, _BumpScale);
                vec3 b = tangentWS.w * cross(normalWS, tangentWS.xyz);
                vec3 n = normalize(mat3(tangentWS.xyz, b, normalWS) * nTS);
            #else
                vec3 n = normalize(normalWS);
            #endif
                fragColor = vec4(n, 0.0);
            }
            #endif
            ENDGLSL
        }
    }
}