GameTech/URP 渲染实战
源码 / Ch30/DebugView.shader
Ch30/DebugView.shader
// 案例 30.1:可切换输出的“调试视图” Shader。把中间量直接画成颜色,是 Shader 调试最快的手段。
// _DebugView:0 最终光照 1 世界法线 2 UV 3 N·L 4 主光阴影 5 切线空间法线贴图 6 世界坐标网格
Shader "Cookbook/Ch30/DebugView"
{
    Properties
    {
        [MainTexture] _BaseMap ("Base Map", 2D) = "white" {}
        [NoScaleOffset][Normal] _BumpMap ("Normal Map", 2D) = "bump" {}
        _BumpScale ("Normal Scale", Float) = 1
        [Enum(Final,0, NormalWS,1, UV,2, NdotL,3, Shadow,4, NormalMapTS,5, WorldGrid,6)] _DebugView ("Debug View", Float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }
        Pass
        {
            Name "ForwardDebug"
            Tags { "LightMode"="UniversalForward" }
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
            #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
            // 需要逐像素源码级调试(RenderDoc/PIX 单步)时打开下面这行;发布前删掉
            // #pragma enable_d3d11_debug_symbols
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
            TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                half _BumpScale;
                half _DebugView;
            CBUFFER_END

            struct Attributes
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float4 tangentOS : TANGENT;
                float2 uv : TEXCOORD0;
            };
            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 positionWS : TEXCOORD1;
                half3 normalWS : TEXCOORD2;
                half4 tangentWS : TEXCOORD3;
            };

            Varyings vert(Attributes input)
            {
                Varyings o;
                VertexPositionInputs pos = GetVertexPositionInputs(input.positionOS.xyz);
                VertexNormalInputs nrm = GetVertexNormalInputs(input.normalOS, input.tangentOS);
                o.positionCS = pos.positionCS;
                o.positionWS = pos.positionWS;
                o.normalWS = nrm.normalWS;
                o.tangentWS = half4(nrm.tangentWS, input.tangentOS.w * GetOddNegativeScale());
                o.uv = TRANSFORM_TEX(input.uv, _BaseMap);
                return o;
            }

            half4 frag(Varyings i) : SV_Target
            {
                half3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, i.uv), _BumpScale);
                half3 bitangentWS = i.tangentWS.w * cross(i.normalWS, i.tangentWS.xyz);
                half3 normalWS = normalize(TransformTangentToWorld(normalTS, half3x3(i.tangentWS.xyz, bitangentWS, i.normalWS)));

                Light light = GetMainLight(TransformWorldToShadowCoord(i.positionWS));
                half ndl = saturate(dot(normalWS, light.direction));
                int view = (int)_DebugView;

                // 约定:方向向量 [-1,1] 映射到 [0,1] 再显示;标量直接显示为灰度
                if (view == 1) return half4(normalWS * 0.5 + 0.5, 1);
                if (view == 2) return half4(frac(i.uv), 0, 1);
                if (view == 3) return half4(ndl.xxx, 1);
                if (view == 4) return half4(light.shadowAttenuation.xxx, 1);
                if (view == 5) return half4(normalTS * 0.5 + 0.5, 1);
                if (view == 6)
                {
                    float3 g = abs(frac(i.positionWS * 2 + 0.5) - 0.5) / fwidth(i.positionWS * 2);
                    half line01 = 1 - saturate(min(g.x, min(g.y, g.z)));
                    return half4(lerp(half3(0.15, 0.15, 0.18), half3(1, 0.6, 0.2), line01), 1);
                }

                half3 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv).rgb;
                half3 color = albedo * (light.color * ndl * light.shadowAttenuation + SampleSH(normalWS));
                return half4(color, 1);
            }
            ENDHLSL
        }
        // 投射阴影直接借用 URP Lit 的 ShadowCaster(会让本 Shader 不兼容 SRP Batcher,调试 Shader 无所谓)
        UsePass "Universal Render Pipeline/Lit/ShadowCaster"
    }
}