--- title: RED阴影系统 date: 2026-05-03 00:00:00 excerpt: 动态/静态阴影分离着色系统,ARC 卡通渲染的核心阴影方案 tags: - ARC - Rendering - Shadow - Toon rating: ⭐ --- # RED 阴影系统 返回 [[Rendering]] ## 概述 RED 阴影系统是 ARC 引擎卡通渲染的核心机制。它将传统 Deferred Lighting 中的阴影处理替换为**阴影着色(Shadow Coloring)**方案——阴影区域不是简单地变暗,而是使用指定的"阴影颜色"进行着色,这是实现赛璐珞风格卡通渲染的关键技术。 ## 核心思路 传统 PBR 阴影:`最终颜色 = 光照颜色 × 阴影衰减` RED 阴影系统:`最终颜色 = lerp(阴影颜色, 光照颜色, 阴影系数)` 同时将**动态阴影**(Shadow Map)和**静态阴影**(Lightmap / Distance Field Shadow)分离处理,允许独立控制两种阴影的着色效果。 ## 实现细节 ### 1. 入口函数 REDDirectionalPixelMain 在 `DeferredLightPixelShaders.usf` 中新增独立的方向光入口: ```hlsl // ASW Change : 2016/10/12 21:35:18 Takuro.K void REDDirectionalPixelMain( float2 InUV : TEXCOORD0, float3 ScreenVector : TEXCOORD1, float4 SVPos : SV_POSITION, out float4 OutColor : SV_Target0 ) { // ... 读取 GBuffer、计算光照衰减 ... OutColor = REDGetShadowColor( WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, GetPerPixelLightAttenuation(InUV), Random, DynamicShadowShade); } ``` `DynamicShadowShade` 是一个 uniform 参数,控制动态阴影的明暗程度。 ### 2. 阴影项分离 REDGetShadowTerms 在 `DeferredLightingCommon.ush` 中将阴影分解为动态和静态两个独立项: ```hlsl void REDGetShadowTerms( FGBufferData GBuffer, FDeferredLightData LightData, float3 WorldPosition, float4 LightAttenuation, out float DynamicShadowTerm, out float StaticShadowTerm) { // 动态阴影:来自 Shadow Map float DynamicShadowFraction = DistanceFromCameraFade(...); DynamicShadowTerm = min( lerp(LightAttenuation.x, 1.0f, DynamicShadowFraction), StaticShadowing); // 静态阴影:来自 Lightmap / Distance Field StaticShadowTerm = StaticShadowing; } ``` ### 3. 阴影着色 REDGetShadowColor 核心函数——使用 `DiffuseColor`(存储在 GBufferD 的 CustomData 中)作为阴影颜色: ```hlsl float4 REDGetShadowColor(...) { float DynamicShadow, StaticShadow; REDGetShadowTerms(GBuffer, LightData, WorldPosition, LightAttenuation, DynamicShadow, StaticShadow); // 动态阴影颜色 = DiffuseColor × DynamicShadowShade float3 DynamicShadowColor = GBuffer.DiffuseColor * DynamicShadowShade; // 静态阴影颜色 = DiffuseColor(不额外缩放) float3 StaticShadowColor = GBuffer.DiffuseColor; StaticShadowColor = lerp(StaticShadowColor, float3(1,1,1), StaticShadow); return float4( lerp(DynamicShadowColor, StaticShadowColor, DynamicShadow), 0.0f); } ``` ### 4. PointLight 的 CustomData 使用 点光源渲染时,将 CustomData(原本存储轮廓线 ID 等数据)重新解释为 DiffuseColor: ```hlsl // ASW Change : 2020/01/14 20:19:00 Takeshi.N ScreenSpaceData.GBuffer.DiffuseColor.rgb = ScreenSpaceData.GBuffer.CustomData.rgb; ``` ## C++ 端支持 在 `LightRendering.cpp` 中: - 新增 `REDDeferredLightPS` Pixel Shader 类,绑定 `DynamicShadowShade` 参数 - 点光源通过 `bPointLightRED` 排序键控制渲染顺序(排在方向光之后) - `RED_CUSTOM_LIGHTING` 宏控制是否启用自定义光照路径 ## 关联文档 - [[RED自定义数据通道]] — DiffuseColor 如何写入 GBufferD - [[自定义光照Pass]] — REDDeferredLightPS 的 C++ 绑定 - [[BGMultColor全局色调]] — 场景全局色调叠加 ## 修改文件列表 | 文件 | 修改类型 | |------|---------| | `Shaders/Private/DeferredLightPixelShaders.usf` | 新增 `REDDirectionalPixelMain` | | `Shaders/Private/DeferredLightingCommon.ush` | 新增 `REDGetShadowTerms`、`REDGetShadowColor` | | `Source/Runtime/Renderer/Private/LightRendering.cpp` | 新增 `REDDeferredLightPS`、点光排序 |