找回密码
 立即注册
首页 业界区 业界 【URP】[实时阴影]计算流程解析

【URP】[实时阴影]计算流程解析

坠矜 2025-9-28 18:42:53
在Unity URP中,实时阴影的工作流程基于‌ShadowMap技术‌实现,主要流程如下:
【从UnityURP开始探索游戏渲染】专栏-直达
一、阴影生成流程

‌阴影贴图(ShadowMap)生成

在光源位置设置虚拟相机,渲染场景深度到纹理:

  • 主光源阴影由ShadowCaster Pass处理,输出深度图到_MainLightShadowmapTexture‌
  • 使用级联阴影(Cascaded Shadow Mapping)提升精度:将ShadowMap划分为2×2图集,对应不同精度等级‌
  1. csharp
  2. // URP核心流程if (主光源开启阴影) {
  3.     MainLightShadowCasterPass.Render();// 生成_MainLightShadowmapTexture
  4. }
复制代码
‌深度值比较

正常渲染时执行:

  • 将像素坐标转换到光源空间获取深度值
  • 采样ShadowMap比较深度:若当前深度 > ShadowMap值,则判定为阴影区域‌
二、关键Pass的作用

ShadowCaster Pass


  • 作用‌:专用于生成阴影贴图
  • 输出目标‌:_MainLightShadowmapTexture(主光源)或自定义ShadowMap
  • Shader要求‌:
  1. hlsl
  2. Pass {
  3.     Tags { "LightMode" = "ShadowCaster" }
  4.     #pragma multi_compile_shadowcaster // 生成SHADOWS_DEPTH/SHADOW_CUBE宏‌
  5.     V2F_SHADOW_CASTER; // 声明数据结构
  6.     TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) // 顶点着色器处理深度偏移‌
  7. }
复制代码
来自于Lit的阴影投射pass
  1. // ShadowCaster 计算灯光的深度贴图,相当于以光的位置主动投射到物体上,形成的偏移阴影。用来投射阴影到其他位置的计算。
  2. // 这里涉及到_ShadowBias在Shadow.hlsl中x分量表示DepthBias深度方向偏移,y分量表示NormalBias法线方向偏移。
  3. Pass
  4. {
  5.     Name "ShadowCaster"
  6.     Tags
  7.     {
  8.         "LightMode" = "ShadowCaster"
  9.     }
  10.     // -------------------------------------
  11.     // Render State Commands
  12.     ZWrite On
  13.     ZTest LEqual
  14.     ColorMask 0
  15.     Cull[_Cull]
  16.     HLSLPROGRAM
  17.     #pragma target 2.0
  18.     // -------------------------------------
  19.     // Shader Stages
  20.     #pragma vertex ShadowPassVertex
  21.     #pragma fragment ShadowPassFragment
  22.     // -------------------------------------
  23.     // Material Keywords
  24.     #pragma shader_feature_local _ALPHATEST_ON
  25.     #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
  26.     //--------------------------------------
  27.     // GPU Instancing
  28.     #pragma multi_compile_instancing
  29.     #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
  30.     // -------------------------------------
  31.     // Universal Pipeline keywords
  32.     // -------------------------------------
  33.     // Unity defined keywords
  34.     #pragma multi_compile_fragment _ LOD_FADE_CROSSFADE
  35.     // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias
  36.     #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
  37.     // -------------------------------------
  38.     // Includes
  39.     #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
  40.     #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
  41.     ENDHLSL
  42. }
复制代码
ShadowCasterPass.hlsl

阴影投射主要计算在顶点计算位置,片元不需要处理纹理颜色阴影返回0给黑色。
  1. #ifndef UNIVERSAL_SHADOW_CASTER_PASS_INCLUDED
  2. #define UNIVERSAL_SHADOW_CASTER_PASS_INCLUDED
  3. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  4. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
  5. #if defined(LOD_FADE_CROSSFADE)
  6.     #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
  7. #endif
  8. // Shadow Casting Light geometric parameters. These variables are used when applying the shadow Normal Bias and are set by UnityEngine.Rendering.Universal.ShadowUtils.SetupShadowCasterConstantBuffer in com.unity.render-pipelines.universal/Runtime/ShadowUtils.cs
  9. // For Directional lights, _LightDirection is used when applying shadow Normal Bias.
  10. // For Spot lights and Point lights, _LightPosition is used to compute the actual light direction because it is different at each shadow caster geometry vertex.
  11. float3 _LightDirection;
  12. float3 _LightPosition;
  13. struct Attributes
  14. {
  15.     float4 positionOS   : POSITION;
  16.     float3 normalOS     : NORMAL;
  17.     float2 texcoord     : TEXCOORD0;
  18.     UNITY_VERTEX_INPUT_INSTANCE_ID
  19. };
  20. struct Varyings
  21. {
  22.     #if defined(_ALPHATEST_ON)
  23.         float2 uv       : TEXCOORD0;
  24.     #endif
  25.     float4 positionCS   : SV_POSITION;
  26.     UNITY_VERTEX_INPUT_INSTANCE_ID
  27. };
  28. float4 GetShadowPositionHClip(Attributes input)
  29. {
  30.     float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
  31.     float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
  32. #if _CASTING_PUNCTUAL_LIGHT_SHADOW
  33.     float3 lightDirectionWS = normalize(_LightPosition - positionWS);
  34. #else
  35.     float3 lightDirectionWS = _LightDirection;
  36. #endif
  37.     float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
  38. #if UNITY_REVERSED_Z
  39.     positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
  40. #else
  41.     positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
  42. #endif
  43.     return positionCS;
  44. }
  45. Varyings ShadowPassVertex(Attributes input)
  46. {
  47.     Varyings output;
  48.     UNITY_SETUP_INSTANCE_ID(input);
  49.     UNITY_TRANSFER_INSTANCE_ID(input, output);
  50.     #if defined(_ALPHATEST_ON)
  51.         output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
  52.     #endif
  53.     output.positionCS = GetShadowPositionHClip(input);
  54.     return output;
  55. }
  56. half4 ShadowPassFragment(Varyings input) : SV_TARGET
  57. {
  58.     UNITY_SETUP_INSTANCE_ID(input);
  59.     #if defined(_ALPHATEST_ON)
  60.         Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
  61.     #endif
  62.     #if defined(LOD_FADE_CROSSFADE)
  63.         LODFadeCrossFade(input.positionCS);
  64.     #endif
  65.     return 0;
  66. }
  67. #endif
复制代码
DepthOnly Pass


  • 作用‌:生成场景深度图(非直接用于阴影)
  • 输出目标‌:_CameraDepthTexture
  • 阴影关联‌:为屏幕空间阴影计算提供场景深度数据,非阴影贴图直接来源‌
三、阴影生成位置


  • 核心Pass‌:阴影完全由LightMode="ShadowCaster"的Pass生成‌
  • 执行阶段‌:在MainLightShadowCasterPass渲染管线阶段完成‌
  • 纹理存储‌:

    • 主光源阴影 → _MainLightShadowmapTexture‌
    • 点光源阴影 → CubeMap形式存储‌

四、深度偏移处理

通过TRANSFER_SHADOW_CASTER_NORMALOFFSET宏:

  • 自动计算法线偏移
  • 解决Shadow Acne(阴影痤疮)和Peter Panning(边缘剥离)问题‌
五、级联阴影优化

URP采用2×2级联图集:

  • 每级对应不同视锥区域
  • 动态分配精度:近距离高精度,远距离低精度‌
  • 通过GetShadowCasterBounds()计算光源影响范围‌
⚠️ 注意事项

  • 物体需包含ShadowCaster Pass才能投射阴影‌
  • 深度测试冲突可能导致阴影缺失,需检查材质配置
【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册