GameTech/URP 渲染实战
源码 / shaders/Ch11/MyPBR_DepthPasses.glsl
shaders/Ch11/MyPBR_DepthPasses.glsl
// MyPBR 的“只写深度”类 Pass:ShadowCaster / DepthOnly / DepthNormals(GLSL 版,对应 Ch11/MyPBR_DepthPasses.hlsl)
// 三者结构几乎一样:变换顶点、(可选)Alpha Clip,DepthNormals 额外输出世界法线。
// 使用前定义 MY_SHADOW_PASS / MY_DEPTH_PASS / MY_DEPTH_NORMALS_PASS 之一,选择本 Pass 的顶点/片元函数。
#ifndef COOKBOOK_MYPBR_DEPTH_PASSES_INCLUDED
#define COOKBOOK_MYPBR_DEPTH_PASSES_INCLUDED

// DepthVaryings:WebGL 不允许结构体做 varying,拆成单独的变量
VARYING vec2 uv;
VARYING vec3 normalWS;
#if defined(_NORMALMAP)
VARYING vec4 tangentWS;
#endif

#ifdef FRAGMENT
void MyAlphaClip(vec2 uv)
{
#if defined(_ALPHATEST_ON)
    float a = texture(_BaseMap, uv).a * _BaseColor.a;
    if (a - _Cutoff < 0.0) discard;
#endif
}
#endif

// URP 在渲染阴影图时设置这两个变量:方向光用 _LightDirection,点/聚光用 _LightPosition
// (网页版核心库 Lighting.glsl 已声明 _LightDirection、_LightPosition、_CastingPunctualLightShadow)
#ifdef VERTEX
void MyShadowVert()
{
    vec3 positionWS = TransformObjectToWorld(positionOS.xyz);
    vec3 nWS        = TransformObjectToWorldNormal(normalOS);
    // HLSL 里是 _CASTING_PUNCTUAL_LIGHT_SHADOW 关键字;网页版是 uniform
    vec3 lightDirWS = _CastingPunctualLightShadow > 0.5 ? normalize(_LightPosition - positionWS) : _LightDirection;
    // 深度偏移 + 法线偏移(数值来自灯光的 Bias 设置),对抗 Shadow Acne
    vec4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, nWS, 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 * positionCS.w);   // GL 的近平面在 z = -w
#endif
    gl_Position = positionCS;
    uv = TransformTex(texcoord0.xy, _BaseMap_ST);
}
#endif

#ifdef FRAGMENT
vec4 MyShadowFrag()
{
    MyAlphaClip(uv);
    return vec4(0.0);
}
#endif

#ifdef VERTEX
void MyDepthVert()
{
    gl_Position = TransformObjectToHClip(positionOS.xyz);
    uv = TransformTex(texcoord0.xy, _BaseMap_ST);
}
#endif

#ifdef FRAGMENT
vec4 MyDepthFrag()
{
    MyAlphaClip(uv);
    return vec4(gl_FragCoord.z);    // ColorMask R:部分平台把深度拷到颜色目标,写 z 即可
}
#endif

#ifdef VERTEX
void MyDepthNormalsVert()
{
    gl_Position = TransformObjectToHClip(positionOS.xyz);
    uv = TransformTex(texcoord0.xy, _BaseMap_ST);
    VertexNormalInputs nrm = GetVertexNormalInputs(normalOS, tangentOS);
    normalWS = nrm.normalWS;
#if defined(_NORMALMAP)
    tangentWS = vec4(nrm.tangentWS, tangentOS.w * GetOddNegativeScale());
#endif
}
#endif

#ifdef FRAGMENT
vec4 MyDepthNormalsFrag()
{
    MyAlphaClip(uv);
#if defined(_NORMALMAP)
    // SSAO、贴花等读 _CameraNormalsTexture,带上法线贴图细节它们才对得上
    vec3 normalTS = UnpackNormalScale(texture(_BumpMap, uv), _BumpScale);
    vec3 bitangent = tangentWS.w * cross(normalWS, tangentWS.xyz);
    vec3 n = TransformTangentToWorld(normalTS, mat3(tangentWS.xyz, bitangent, normalWS));
#else
    vec3 n = normalWS;
#endif
    return vec4(NormalizeNormalPerPixel(n), 0.0);   // URP 14 存未编码的世界法线
}
#endif

#endif