GameTech/URP 渲染实战
源码 / shaders/Ch08/EnvReflection.glsl
shaders/Ch08/EnvReflection.glsl
// 只看“间接高光”:按粗糙度从预过滤 cubemap 的不同 mip 取环境反射。(GLSL 版,对应 Ch08/EnvReflection.shader)
// 模式 0:URP 的 GlossyEnvironmentReflection(探针、混合、盒体投影全包);
// 模式 1:手动采样全局环境 cubemap,粗糙度 → mip 用线性映射(对照用);
// 模式 2:手动采样,使用 URP 的非线性映射 PerceptualRoughnessToMipmapLevel。
Shader "Cookbook/Ch08/EnvReflection"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        GLSLINCLUDE
        uniform vec4  _Tint;
        uniform float _Roughness;
        uniform float _Mode;
        ENDGLSL

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode"="UniversalForwardOnly" }
            GLSLPROGRAM
            VARYING vec3 positionWS;
            VARYING vec3 normalWS;

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

            #ifdef FRAGMENT
            // 网页版没有反射探针,全局环境反射就是 unity_SpecCube0;URP 里对应的名字是 _GlossyEnvironmentCubeMap
            #define _GlossyEnvironmentCubeMap unity_SpecCube0
            #define _GlossyEnvironmentCubeMap_HDR unity_SpecCube0_HDR

            // 手动版:全局环境反射(Lighting 窗口里的 Environment Reflections)由 URP 设置为
            // _GlossyEnvironmentCubeMap,它的 mip 链是按粗糙度预过滤过的
            vec3 SampleEnvManual(vec3 R, float perceptualRoughness, bool urpCurve)
            {
                float mip = urpCurve
                    ? PerceptualRoughnessToMipmapLevel(perceptualRoughness)   // r·(1.7-0.7r)·6
                    : perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;          // 线性:r·6
                vec4 encoded = textureLod(_GlossyEnvironmentCubeMap, R, mip);
                // HDR 解码:RGBM/dLDR 编码的 cubemap 需要 _HDR 参数还原,浮点格式时它只是乘一个强度
                return DecodeHDREnvironment(encoded, _GlossyEnvironmentCubeMap_HDR);
            }

            void main()
            {
                vec3 N = normalize(normalWS);
                vec3 V = GetWorldSpaceNormalizeViewDir(positionWS);
                vec3 R = reflect(-V, N);
                vec3 c;
                if (_Mode < 0.5)
                {
                    c = GlossyEnvironmentReflection(R, positionWS, _Roughness, 1.0);
                }
                else
                {
                    c = SampleEnvManual(R, _Roughness, _Mode > 1.5);
                }
                fragColor = vec4(c * _Tint.rgb, 1.0);
            }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On ColorMask R
            GLSLPROGRAM
            #include "Ch08/Ch08Passes.glsl"
            #ifdef VERTEX
            void main() { gl_Position = Ch08DepthVert(); }
            #endif
            #ifdef FRAGMENT
            void main() { fragColor = Ch08NullFrag(); }
            #endif
            ENDGLSL
        }
    }
}