GameTech/URP 渲染实战

案例 6.7附加光阴影进阶

目标:理解点光、聚光阴影的存储方式,让多光源 Shader 正确接收它们。

附加光的阴影全部放在一张阴影图集 _AdditionalLightsShadowmapTexture 里:聚光灯占 1 个图块(透视投影),点光源占 6 个图块(立方体的 6 个面,每面 90° 多一点的透视投影,多出的角度用来给软阴影的滤波核留边)。每个图块的分辨率由灯光的 Shadow Resolution 档位(Low / Medium / High,像素数在 Asset 里设置)决定,图集放不下所有图块时 URP 会自动缩小它们(具体策略以实际版本为准)。每盏灯的阴影参数打包在 _AdditionalShadowParams[lightIndex] 里:x 是阴影强度,y 是软阴影质量,z 表示是否点光,w 是它的第一个图块的下标(−1 表示不投影)。

采样逻辑在 AdditionalLightRealtimeShadow 里:对点光源,先用 CubeMapFaceID(−lightDirection) 求出像素位于立方体的哪个面,把图块下标加上面号,再用对应的矩阵变换和采样。好消息是,这些都封装在 GetAdditionalLight(i, positionWS, shadowMask) 这个重载里——只要 Shader 声明了 _ADDITIONAL_LIGHT_SHADOWS,调用它返回的 light.shadowAttenuation 就已经是阴影结果。

#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS

LIGHT_LOOP_BEGIN(pixelLightCount)
    // 带 shadowMask 参数的重载:内部调用 AdditionalLightShadow(),还会乘上 Cookie
    Light light = GetAdditionalLight(lightIndex, inputData.positionWS, shadowMask);
    color += Shade(light, ...);   // Shade 里已经乘了 light.shadowAttenuation
LIGHT_LOOP_END
图 6-19夜景:中央一盏暖色点光、左前方一盏冷色聚光,场景使用案例 6.9 的 ClassicLit。左:两盏灯都关闭阴影,光穿过柱子;右:开启软阴影,点光在六个方向投下放射状的影子,聚光的影子拉得很长
注意附加光阴影要同时满足:URP Asset 勾选 Lighting › Additional Lights › Cast Shadows;灯光组件的 Shadow Type 不是 No Shadows;灯光是逐像素光(逐顶点附加光不支持阴影);Shader 声明了 _ADDITIONAL_LIGHT_SHADOWS。点光源要渲染 6 次阴影,开销是聚光灯的 6 倍,移动端要非常克制。