GameTech/URP 渲染实战
源码 / shaders/Ch28/ReconstructWorldPos.glsl
shaders/Ch28/ReconstructWorldPos.glsl
// 案例 28.1:从深度重建世界坐标的两种方法,并把结果可视化。
// Pass 0:逆 VP 矩阵法,输出 frac(positionWS);Pass 1:视锥射线法,在原画面上叠加 1 米世界网格;
// Pass 2:两种方法的差值放大显示(用来验证两者一致)。
Shader "Cookbook/Ch28/ReconstructWorldPos"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
        ZWrite Off ZTest Always Cull Off Blend Off

        GLSLINCLUDE
        uniform vec4 _GridColor;
        uniform float _GridWidth;
        uniform float _DiffScale;
        ENDGLSL

        Pass
        {
            Name "InvVP"
            GLSLPROGRAM
            #include "Ch28/ScreenSpaceCommon.glsl"
            #ifdef FRAGMENT
            vec4 Frag()
            {
                vec2 uv = texcoord;
                vec4 sceneColor = SamplePointClamp(_BlitTexture, uv);
                float depth = SampleDeviceDepth(uv);
                if (IsSkyDepth(depth)) return sceneColor * 0.35;   // 天空没有几何,压暗区分
                vec3 positionWS = ReconstructPositionWS(uv, depth);
                // +0.5:避开地面 y=0 这种整数坐标,frac 在 0/1 之间来回跳会产生噪点
                return vec4(fract(positionWS + 0.5), 1.0);
            }
            void main() { fragColor = Frag(); }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "ViewRay"
            GLSLPROGRAM
            #define USE_VIEW_RAY
            #include "Ch28/ScreenSpaceCommon.glsl"
            #ifdef FRAGMENT
            vec4 Frag()
            {
                vec2 uv = texcoord;
                vec4 sceneColor = SamplePointClamp(_BlitTexture, uv);
                float rawDepth = SampleSceneDepth(uv);
                if (IsSkyDepth(rawDepth)) return sceneColor;
                vec3 positionWS = ReconstructPositionWSFromRay(farRayWS, rawDepth);

                // 1 米网格线:用 fwidth 把线宽换算成像素,远近粗细一致
                vec3 dist = abs(fract(positionWS + 0.5) - 0.5);
                vec3 width = fwidth(positionWS) * _GridWidth;
                vec3 lines = 1.0 - smoothstep(width * 0.5, width * 1.5, dist);
                float grid = saturate(max(lines.x, max(lines.y, lines.z)));
                return mix(sceneColor, _GridColor, grid * 0.85);
            }
            void main() { fragColor = Frag(); }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "Diff"
            GLSLPROGRAM
            #define USE_VIEW_RAY
            #include "Ch28/ScreenSpaceCommon.glsl"
            #ifdef FRAGMENT
            void main()
            {
                vec2 uv = texcoord;
                float rawDepth = SampleSceneDepth(uv);
                vec3 a = ReconstructPositionWS(uv, SampleDeviceDepth(uv));
                vec3 b = ReconstructPositionWSFromRay(farRayWS, rawDepth);
                fragColor = vec4(saturate(abs(a - b) * _DiffScale), 1.0);
            }
            #endif
            ENDGLSL
        }
    }
}