127 lines
4.2 KiB
Markdown
127 lines
4.2 KiB
Markdown
---
|
||
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`、点光排序 |
|