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

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

    正在检查是否收录...

在Unity URP中,实时阴影的工作流程基于‌

ShadowMap技术

‌实现,主要流程如下:

【从UnityURP开始探索游戏渲染】

专栏-直达

一、阴影生成流程

‌阴影贴图(ShadowMap)生成

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

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

‌深度值比较

正常渲染时执行:

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

二、关键Pass的作用

ShadowCaster Pass

  • 作用

    ‌:专用于生成阴影贴图
  • 输出目标

    ‌:_MainLightShadowmapTexture(主光源)或自定义ShadowMap
  • Shader要求

    ‌:
hlsl Pass { Tags { "LightMode" = "ShadowCaster" } #pragma multi_compile_shadowcaster // 生成SHADOWS_DEPTH/SHADOW_CUBE宏‌ V2F_SHADOW_CASTER; // 声明数据结构 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) // 顶点着色器处理深度偏移‌ } 

来自于Lit的阴影投射pass

// ShadowCaster 计算灯光的深度贴图,相当于以光的位置主动投射到物体上,形成的偏移阴影。用来投射阴影到其他位置的计算。 // 这里涉及到_ShadowBias在Shadow.hlsl中x分量表示DepthBias深度方向偏移,y分量表示NormalBias法线方向偏移。 Pass { Name "ShadowCaster" Tags { "LightMode" = "ShadowCaster" } // ------------------------------------- // Render State Commands ZWrite On ZTest LEqual ColorMask 0 Cull[_Cull] HLSLPROGRAM #pragma target 2.0 // ------------------------------------- // Shader Stages #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment // ------------------------------------- // Material Keywords #pragma shader_feature_local _ALPHATEST_ON #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" // ------------------------------------- // Universal Pipeline keywords // ------------------------------------- // Unity defined keywords #pragma multi_compile_fragment _ LOD_FADE_CROSSFADE // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW // ------------------------------------- // Includes #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl" ENDHLSL } 

ShadowCasterPass.hlsl

阴影投射主要计算在顶点计算位置,片元不需要处理纹理颜色阴影返回0给黑色。

#ifndef UNIVERSAL_SHADOW_CASTER_PASS_INCLUDED #define UNIVERSAL_SHADOW_CASTER_PASS_INCLUDED #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl" #if defined(LOD_FADE_CROSSFADE) #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl" #endif // 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 // For Directional lights, _LightDirection is used when applying shadow Normal Bias. // 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. float3 _LightDirection; float3 _LightPosition; struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { #if defined(_ALPHATEST_ON) float2 uv : TEXCOORD0; #endif float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID }; float4 GetShadowPositionHClip(Attributes input) { float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(input.normalOS); #if _CASTING_PUNCTUAL_LIGHT_SHADOW float3 lightDirectionWS = normalize(_LightPosition - positionWS); #else float3 lightDirectionWS = _LightDirection; #endif float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS)); #if UNITY_REVERSED_Z positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE); #else positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE); #endif return positionCS; } Varyings ShadowPassVertex(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); #if defined(_ALPHATEST_ON) output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); #endif output.positionCS = GetShadowPositionHClip(input); return output; } half4 ShadowPassFragment(Varyings input) : SV_TARGET { UNITY_SETUP_INSTANCE_ID(input); #if defined(_ALPHATEST_ON) Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff); #endif #if defined(LOD_FADE_CROSSFADE) LODFadeCrossFade(input.positionCS); #endif return 0; } #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开始探索游戏渲染】

专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

  • 本文作者:WAP站长网
  • 本文链接: https://wapzz.net/post-27667.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
本站部分内容来源于网络转载,仅供学习交流使用。如涉及版权问题,请及时联系我们,我们将第一时间处理。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
0
0
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
2.8W+
9
1
2
WAP站长官方

VTK开发笔记(三):熟悉VTK开发流程,编写球体,多半透明球体Demo

上一篇

Why框架,是苦逼程序员的终极福音

下一篇
评论区
内容为空

这一切,似未曾拥有

  • 复制图片
按住ctrl可打开默认菜单