GameTech/URP 渲染实战
源码 / Ch11/MyPBR_DepthPasses.hlsl
Ch11/MyPBR_DepthPasses.hlsl
// MyPBR 的“只写深度”类 Pass:ShadowCaster / DepthOnly / DepthNormals
// 三者结构几乎一样:变换顶点、(可选)Alpha Clip,DepthNormals 额外输出世界法线。
#ifndef COOKBOOK_MYPBR_DEPTH_PASSES_INCLUDED
#define COOKBOOK_MYPBR_DEPTH_PASSES_INCLUDED

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"

struct DepthAttributes
{
    float4 positionOS : POSITION;
    float3 normalOS   : NORMAL;
    float4 tangentOS  : TANGENT;
    float2 texcoord   : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct DepthVaryings
{
    float4 positionCS : SV_POSITION;
    float2 uv         : TEXCOORD0;
    half3  normalWS   : TEXCOORD1;
#if defined(_NORMALMAP)
    half4  tangentWS  : TEXCOORD2;
#endif
    UNITY_VERTEX_INPUT_INSTANCE_ID
    UNITY_VERTEX_OUTPUT_STEREO
};

void MyAlphaClip(float2 uv)
{
#if defined(_ALPHATEST_ON)
    half a = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv).a * _BaseColor.a;
    clip(a - _Cutoff);
#endif
}

// URP 在渲染阴影图时设置这两个变量:方向光用 _LightDirection,点/聚光用 _LightPosition
float3 _LightDirection;
float3 _LightPosition;

DepthVaryings MyShadowVert(DepthAttributes input)
{
    DepthVaryings o = (DepthVaryings)0;
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_TRANSFER_INSTANCE_ID(input, o);

    float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
    float3 normalWS   = TransformObjectToWorldNormal(input.normalOS);
#if defined(_CASTING_PUNCTUAL_LIGHT_SHADOW)
    float3 lightDirWS = normalize(_LightPosition - positionWS);
#else
    float3 lightDirWS = _LightDirection;
#endif
    // 深度偏移 + 法线偏移(数值来自灯光的 Bias 设置),对抗 Shadow Acne
    float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirWS));
    // 把被近裁剪面切掉的投射体压到近平面上(Shadow Pancaking),否则阴影会出洞
#if UNITY_REVERSED_Z
    positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#else
    positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#endif
    o.positionCS = positionCS;
    o.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
    return o;
}

half4 MyShadowFrag(DepthVaryings i) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(i);
    MyAlphaClip(i.uv);
    return 0;
}

DepthVaryings MyDepthVert(DepthAttributes input)
{
    DepthVaryings o = (DepthVaryings)0;
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_TRANSFER_INSTANCE_ID(input, o);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    o.positionCS = TransformObjectToHClip(input.positionOS.xyz);
    o.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
    return o;
}

half MyDepthFrag(DepthVaryings i) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(i);
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    MyAlphaClip(i.uv);
    return i.positionCS.z;    // ColorMask R:部分平台把深度拷到颜色目标,写 z 即可
}

DepthVaryings MyDepthNormalsVert(DepthAttributes input)
{
    DepthVaryings o = (DepthVaryings)0;
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_TRANSFER_INSTANCE_ID(input, o);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    o.positionCS = TransformObjectToHClip(input.positionOS.xyz);
    o.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
    VertexNormalInputs nrm = GetVertexNormalInputs(input.normalOS, input.tangentOS);
    o.normalWS = nrm.normalWS;
#if defined(_NORMALMAP)
    o.tangentWS = half4(nrm.tangentWS, input.tangentOS.w * GetOddNegativeScale());
#endif
    return o;
}

void MyDepthNormalsFrag(DepthVaryings i
    , out half4 outNormalWS : SV_Target0
#if defined(_WRITE_RENDERING_LAYERS)
    , out float4 outRenderingLayers : SV_Target1
#endif
    )
{
    UNITY_SETUP_INSTANCE_ID(i);
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    MyAlphaClip(i.uv);
#if defined(_NORMALMAP)
    // SSAO、贴花等读 _CameraNormalsTexture,带上法线贴图细节它们才对得上
    half3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, i.uv), _BumpScale);
    float3 bitangent = i.tangentWS.w * cross(i.normalWS, i.tangentWS.xyz);
    float3 normalWS = TransformTangentToWorld(normalTS, half3x3(i.tangentWS.xyz, bitangent, i.normalWS));
#else
    float3 normalWS = i.normalWS;
#endif
    outNormalWS = half4(NormalizeNormalPerPixel(normalWS), 0.0);   // URP 14 存未编码的世界法线
#if defined(_WRITE_RENDERING_LAYERS)
    outRenderingLayers = float4(EncodeMeshRenderingLayer(GetMeshRenderingLayer()), 0, 0, 0);
#endif
}

#endif