GameTech/URP 渲染实战
源码 / shaders/Ch10/SpecCompare.glsl
shaders/Ch10/SpecCompare.glsl
// 第 10 章:URP 的 DirectBRDFSpecular(移动端近似)vs 标准 GGX · 高度相关 Smith · Schlick。(GLSL 版,对应 Ch10/SpecCompare.shader)
// 只输出主光的直接高光,参照组完全用 core 包 BSDF.hlsl 里的标准函数(网页版抄在 Ch10/CoreBSDF.glsl)。
Shader "Cookbook/Ch10/SpecCompare"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }
        Pass
        {
            Tags { "LightMode"="UniversalForward" }
            GLSLPROGRAM
            #include "Ch10/CoreBSDF.glsl"

            uniform float _Mode, _Smoothness, _Exposure;
            uniform vec4 _F0;

            VARYING vec3 positionWS;
            VARYING vec3 normalWS;

            #ifdef VERTEX
            void main()
            {
                positionWS = TransformObjectToWorld(positionOS.xyz);
                gl_Position = TransformWorldToHClip(positionWS);
                normalWS = TransformObjectToWorldNormal(normalOS);
            }
            #endif

            #ifdef FRAGMENT
            void main()
            {
                vec3 N = normalize(normalWS);
                vec3 V = GetWorldSpaceNormalizeViewDir(positionWS);
                Light light = GetMainLight();
                vec3 L = light.direction;
                float NoL = saturate(dot(N, L));

                // 用 URP 自己的初始化:金属度 1、albedo = F0,于是 brdf.specular = F0、brdf.diffuse = 0
                float alpha = 1.0;
                BRDFData brdf;
                InitializeBRDFData(_F0.rgb, 1.0, vec3(0.0), _Smoothness, alpha, brdf);

                vec3 spec;   // 已经乘了 π 的“Unity 约定”镜面项,乘 lightColor·NoL 即出射辐射率
                if (_Mode < 0.5)
                {
                    spec = brdf.specular * DirectBRDFSpecular(brdf, N, L, V);
                }
                else
                {
                    vec3 H = SafeNormalize(L + V);
                    float NoV = max(dot(N, V), 1e-4), NoH = saturate(dot(N, H)), VoH = saturate(dot(V, H));
                    float a = brdf.roughness;                                   // α,与 URP 用同一个值
                    float DV = D_GGX(NoH, a) * V_SmithJointGGX(NoL, NoV, a);    // core/BSDF.hlsl
                    spec = PI * DV * F_Schlick(_F0.rgb, VoH);
                }

                vec3 c = spec * light.color * NoL;
                fragColor = vec4(1.0 - exp(-c * _Exposure), 1.0);
            }
            #endif
            ENDGLSL
        }
    }
}