2026-05-03 20:37:58 +08:00
|
|
|
|
---
|
|
|
|
|
|
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全局色调]] — 场景全局色调叠加
|
|
|
|
|
|
|
2026-05-03 21:38:46 +08:00
|
|
|
|
## 完整代码解析
|
2026-05-03 20:37:58 +08:00
|
|
|
|
|
2026-05-03 21:38:46 +08:00
|
|
|
|
### DeferredLightPixelShaders.usf
|
|
|
|
|
|
|
|
|
|
|
|
#### DynamicShadowShade uniform 声明
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2019/02/05 20:37:00 Takeshi.N
|
|
|
|
|
|
// 动态阴影明暗控制参数,从 C++ 端传入
|
|
|
|
|
|
// 0.0 = 动态阴影区域完全黑色
|
|
|
|
|
|
// 1.0 = 无动态阴影变暗效果
|
|
|
|
|
|
float DynamicShadowShade;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### REDDirectionalPixelMain — 方向光阴影着色入口
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2016/10/12 21:35:18 Takuro.K
|
|
|
|
|
|
// 专用的方向光阴影着色 Pixel Shader 入口
|
|
|
|
|
|
// 与标准 DeferredLightPixelMain 并行存在,由 C++ 端选择调用
|
|
|
|
|
|
void REDDirectionalPixelMain(
|
|
|
|
|
|
float2 InUV : TEXCOORD0, // 屏幕空间 UV
|
|
|
|
|
|
float3 ScreenVector : TEXCOORD1, // 屏幕空间到世界空间的方向向量
|
|
|
|
|
|
float4 SVPos : SV_POSITION, // 屏幕位置
|
|
|
|
|
|
out float4 OutColor : SV_Target0 // 输出:阴影颜色(不是光照颜色)
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
|
|
|
|
|
OutColor = float4(1,1,1,0); // 默认白色 = 无阴影
|
|
|
|
|
|
float3 CameraVector = normalize(ScreenVector);
|
|
|
|
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(InUV);
|
|
|
|
|
|
|
|
|
|
|
|
// 只处理使用 Deferred Shading 的像素(ShadingModelID > 0)
|
|
|
|
|
|
BRANCH if( ScreenSpaceData.GBuffer.ShadingModelID > 0
|
|
|
|
|
|
#if USE_LIGHTING_CHANNELS
|
|
|
|
|
|
&& (GetLightingChannelMask(InUV) & DeferredLightUniforms.LightingChannelMask)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
|
|
|
|
|
float SceneDepth = CalcSceneDepth(InUV);
|
|
|
|
|
|
// 从屏幕空间重建世界坐标
|
|
|
|
|
|
float3 WorldPosition = ScreenVector * SceneDepth + View.WorldCameraOrigin;
|
|
|
|
|
|
FDeferredLightData LightData = SetupLightDataForStandardDeferred();
|
|
|
|
|
|
|
|
|
|
|
|
// 生成随机数用于阴影抖动
|
|
|
|
|
|
uint2 Random = ScrambleTEA( uint2( SVPos.xy ) );
|
|
|
|
|
|
Random.x ^= View.Random;
|
|
|
|
|
|
Random.y ^= View.Random;
|
|
|
|
|
|
|
|
|
|
|
|
// 核心:调用 REDGetShadowColor 计算阴影着色
|
|
|
|
|
|
// 注意输出的是"阴影颜色"而非"光照颜色"
|
|
|
|
|
|
OutColor = REDGetShadowColor(
|
|
|
|
|
|
WorldPosition, CameraVector,
|
|
|
|
|
|
ScreenSpaceData.GBuffer,
|
|
|
|
|
|
ScreenSpaceData.AmbientOcclusion,
|
|
|
|
|
|
ScreenSpaceData.GBuffer.ShadingModelID,
|
|
|
|
|
|
LightData,
|
|
|
|
|
|
GetPerPixelLightAttenuation(InUV),
|
|
|
|
|
|
Random,
|
|
|
|
|
|
DynamicShadowShade); // 传入动态阴影明暗参数
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 点光源 CustomData 覆写
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2020/01/14 20:19:00 Takeshi.N
|
|
|
|
|
|
// 点光源渲染时,将 GBufferD 中存储的 CustomData 重新解释为 DiffuseColor
|
|
|
|
|
|
// 这样点光源的阴影着色可以使用与方向光相同的机制
|
|
|
|
|
|
ScreenSpaceData.GBuffer.DiffuseColor.rgb = ScreenSpaceData.GBuffer.CustomData.rgb;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 点光源 BGMultColor 应用
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2020/07/07 16:41:00 Takeshi.N
|
|
|
|
|
|
// 对点光源输出应用全局色调调制
|
|
|
|
|
|
OutColor.rgb *= View.BGMultColor.rgb; // RGB 颜色乘算
|
|
|
|
|
|
float Grayscale = dot(OutColor.rgb, float3(0.299f, 0.587f, 0.114f)); // 计算亮度
|
|
|
|
|
|
OutColor.rgb = lerp( // 饱和度控制
|
|
|
|
|
|
float3(Grayscale, Grayscale, Grayscale), // 灰度版本
|
|
|
|
|
|
OutColor.rgb, // 原色版本
|
|
|
|
|
|
View.BGMultColor.a); // A 通道控制饱和度
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### DeferredLightingCommon.ush
|
|
|
|
|
|
|
|
|
|
|
|
#### 阴影合成修改
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2018/11/13 17:13:00 Takeshi.N
|
|
|
|
|
|
// 原始公式:Shadow = lerp(DynamicShadow, StaticShadow, FadeFraction)
|
|
|
|
|
|
// 问题:距离远时 DynamicShadow 淡出后只剩 StaticShadow,
|
|
|
|
|
|
// 但动态阴影区域可能比静态阴影更暗(StaticShadow=1),导致阴影突然消失
|
|
|
|
|
|
//
|
|
|
|
|
|
// 新公式:Shadow = min(lerp(DynamicShadow, 1.0, FadeFraction), StaticShadow)
|
|
|
|
|
|
// 效果:动态阴影淡出后取 min(1.0, StaticShadow) = StaticShadow
|
|
|
|
|
|
// 动态阴影存在时取 min(DynamicShadow, StaticShadow) = 两者中更暗的
|
|
|
|
|
|
Shadow.SurfaceShadow = min(
|
|
|
|
|
|
lerp(LightAttenuation.x, 1.0f, DynamicShadowFraction), // 动态阴影淡出到 1.0
|
|
|
|
|
|
StaticShadowing); // 与静态阴影取 min
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### REDGetShadowTerms — 阴影项分离
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2019/02/05 20:37:00 Takeshi.N
|
|
|
|
|
|
// 将阴影分解为独立的动态和静态两项,供 REDGetShadowColor 分别着色
|
|
|
|
|
|
void REDGetShadowTerms(
|
|
|
|
|
|
FGBufferData GBuffer,
|
|
|
|
|
|
FDeferredLightData LightData,
|
|
|
|
|
|
float3 WorldPosition,
|
|
|
|
|
|
float4 LightAttenuation, // Shadow Map 衰减值
|
|
|
|
|
|
out float DynamicShadowTerm, // 输出:动态阴影项 (0=全阴影, 1=无阴影)
|
|
|
|
|
|
out float StaticShadowTerm) // 输出:静态阴影项
|
|
|
|
|
|
{
|
|
|
|
|
|
// 从 GBuffer 获取静态阴影(Lightmap / Distance Field)
|
|
|
|
|
|
float UsesStaticShadowMap = dot(LightData.ShadowMapChannelMask, float4(1, 1, 1, 1));
|
|
|
|
|
|
float StaticShadowing = lerp(1,
|
|
|
|
|
|
dot(GBuffer.PrecomputedShadowFactors, LightData.ShadowMapChannelMask),
|
|
|
|
|
|
UsesStaticShadowMap);
|
|
|
|
|
|
|
|
|
|
|
|
if (LightData.bRadialLight)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 点光源/聚光灯:直接使用 LightAttenuation.zw
|
|
|
|
|
|
DynamicShadowTerm = LightAttenuation.z * StaticShadowing;
|
|
|
|
|
|
StaticShadowTerm = LightAttenuation.w * StaticShadowing;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 方向光:根据距离淡化动态阴影
|
|
|
|
|
|
float DynamicShadowFraction = DistanceFromCameraFade(
|
|
|
|
|
|
GBuffer.Depth, LightData, WorldPosition, View.WorldCameraOrigin);
|
|
|
|
|
|
|
|
|
|
|
|
// 动态阴影:距离远时淡化到 1.0(无阴影)
|
|
|
|
|
|
DynamicShadowTerm = lerp(LightAttenuation.x, 1.0f, DynamicShadowFraction);
|
|
|
|
|
|
// 静态阴影:不受距离影响
|
|
|
|
|
|
StaticShadowTerm = StaticShadowing;
|
|
|
|
|
|
|
|
|
|
|
|
// 叠加光照函数 (Light Function)
|
|
|
|
|
|
DynamicShadowTerm *= LightAttenuation.z;
|
|
|
|
|
|
StaticShadowTerm *= LightAttenuation.z;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### REDGetShadowColor — 核心阴影着色函数
|
|
|
|
|
|
|
|
|
|
|
|
```hlsl
|
|
|
|
|
|
// ASW Change : 2016/10/12 21:35:18 Takuro.K
|
|
|
|
|
|
// 核心函数:将阴影从"衰减"转变为"着色"
|
|
|
|
|
|
// 传统 PBR:最终颜色 = 光照 × 阴影衰减(变暗)
|
|
|
|
|
|
// RED 系统:最终颜色 = lerp(阴影颜色, 光照颜色, 阴影系数)(变色)
|
|
|
|
|
|
float4 REDGetShadowColor(
|
|
|
|
|
|
float3 WorldPosition,
|
|
|
|
|
|
float3 CameraVector,
|
|
|
|
|
|
FGBufferData GBuffer,
|
|
|
|
|
|
float AmbientOcclusion,
|
|
|
|
|
|
uint ShadingModelID,
|
|
|
|
|
|
FDeferredLightData LightData,
|
|
|
|
|
|
float4 LightAttenuation,
|
|
|
|
|
|
uint2 Random,
|
|
|
|
|
|
float DynamicShadowShade) // 动态阴影明暗参数
|
|
|
|
|
|
{
|
|
|
|
|
|
float DynamicShadow = 1; // 动态阴影项(1=无阴影)
|
|
|
|
|
|
float StaticShadow = 1; // 静态阴影项
|
|
|
|
|
|
|
|
|
|
|
|
BRANCH
|
|
|
|
|
|
if (LightData.ShadowedBits)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 有阴影贴图时:分离计算动态和静态阴影
|
|
|
|
|
|
REDGetShadowTerms(GBuffer, LightData, WorldPosition,
|
|
|
|
|
|
LightAttenuation, DynamicShadow, StaticShadow);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 无阴影贴图时:使用 AO 作为阴影近似
|
|
|
|
|
|
DynamicShadow = AmbientOcclusion;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 动态阴影颜色 = DiffuseColor × DynamicShadowShade
|
|
|
|
|
|
// DiffuseColor 来自 GBufferD.CustomData(美术指定的阴影基色)
|
|
|
|
|
|
// DynamicShadowShade 控制暗度(0=全黑, 1=与阴影基色相同)
|
|
|
|
|
|
float3 DynamicShadowColor = GBuffer.DiffuseColor * DynamicShadowShade;
|
|
|
|
|
|
|
|
|
|
|
|
// 静态阴影颜色 = DiffuseColor(不额外缩放)
|
|
|
|
|
|
float3 StaticShadowColor = GBuffer.DiffuseColor;
|
|
|
|
|
|
|
|
|
|
|
|
// 静态阴影:从阴影颜色到白色(无阴影)的过渡
|
|
|
|
|
|
StaticShadowColor = lerp(StaticShadowColor, float3(1,1,1), StaticShadow);
|
|
|
|
|
|
|
|
|
|
|
|
// 最终合成:动态阴影颜色到静态阴影颜色的过渡
|
|
|
|
|
|
// DynamicShadow=0 时显示动态阴影颜色
|
|
|
|
|
|
// DynamicShadow=1 时显示静态阴影颜色(可能已经过渡到白色)
|
|
|
|
|
|
return float4(lerp(DynamicShadowColor, StaticShadowColor, DynamicShadow), 0.0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### C++ 端实现
|
|
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
|
// LightRendering.cpp — REDDeferredLightPS 类定义
|
|
|
|
|
|
// ASW Change : 2018/12/18 20:59:02 Kazuhito
|
|
|
|
|
|
// 继承标准 FDeferredLightPS,复用所有 permutation 参数
|
|
|
|
|
|
class REDDeferredLightPS : public FDeferredLightPS
|
|
|
|
|
|
{
|
|
|
|
|
|
DECLARE_GLOBAL_SHADER(REDDeferredLightPS)
|
|
|
|
|
|
|
|
|
|
|
|
REDDeferredLightPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
|
|
|
|
: FDeferredLightPS(Initializer)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ASW: 绑定 DynamicShadowShade uniform 参数
|
|
|
|
|
|
DynamicShadowShade.Bind(Initializer.ParameterMap, TEXT("DynamicShadowShade"));
|
|
|
|
|
|
}
|
|
|
|
|
|
REDDeferredLightPS() {}
|
|
|
|
|
|
|
|
|
|
|
|
// DynamicShadowShade 参数成员
|
|
|
|
|
|
LAYOUT_FIELD(FShaderParameter, DynamicShadowShade);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 注册 Shader:绑定到 DeferredLightPixelShaders.usf 的 REDDirectionalPixelMain 入口
|
|
|
|
|
|
#define RED_CUSTOM_LIGHTING 1
|
|
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(REDDeferredLightPS,
|
|
|
|
|
|
"/Engine/Private/DeferredLightPixelShaders.usf",
|
|
|
|
|
|
"REDDirectionalPixelMain", SF_Pixel);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
|
// LightRendering.cpp — DynamicShadowShade 参数设置
|
|
|
|
|
|
// 方向光:有预计算光照时 shade=0.3(阴影较暗),无预计算时 shade=1.0(无额外变暗)
|
|
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, DynamicShadowShade,
|
|
|
|
|
|
LightSceneInfo->IsPrecomputedLightingValid() ? 0.3f : 1.0f);
|
|
|
|
|
|
|
|
|
|
|
|
// 点光源:shade 固定为 1.0(不额外变暗)
|
|
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, DynamicShadowShade, 1.f);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
|
// LightRendering.cpp — 点光源排序
|
|
|
|
|
|
// ASW Change : 2020/10/22 Takeshi.N
|
|
|
|
|
|
// 点光源在方向光之后渲染(方向光先完成阴影着色,点光源再叠加)
|
|
|
|
|
|
SortedLightInfo->SortKey.Fields.bPointLightRED =
|
|
|
|
|
|
(LightSceneInfoCompact.LightType != LightType_Directional);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
|
// LightRendering.cpp — 方向光渲染路径(RED_CUSTOM_LIGHTING)
|
|
|
|
|
|
// 混合模式改为 Multiply(DestColor × SourceColor)
|
|
|
|
|
|
// 标准 UE4 用 Additive,RED 用 Multiply 因为阴影颜色系统输出的是"乘算遮罩"
|
|
|
|
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<
|
|
|
|
|
|
CW_RGBA, BO_Add,
|
|
|
|
|
|
BF_DestColor, BF_Zero, // RGB: Dest × Source(乘法混合)
|
|
|
|
|
|
BO_Add, BF_One, BF_One // Alpha: 加法
|
|
|
|
|
|
>::GetRHI();
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 REDDeferredLightPS 替代标准 FDeferredLightPS
|
|
|
|
|
|
TShaderMapRef<REDDeferredLightPS> PixelShader(View.ShaderMap, PermutationVector);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 代码修改情况
|
|
|
|
|
|
|
|
|
|
|
|
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
|
|
|
|
|
|---------|------|---------|---------|
|
|
|
|
|
|
| `Shaders/Private/DeferredLightPixelShaders.usf` | L106 | 新增 | `DynamicShadowShade` uniform 声明 |
|
|
|
|
|
|
| `Shaders/Private/DeferredLightPixelShaders.usf` | L109~L145 | 新增 | `REDDirectionalPixelMain` 方向光阴影着色入口函数 |
|
|
|
|
|
|
| `Shaders/Private/DeferredLightPixelShaders.usf` | L236~L239 | 新增 | 点光源 CustomData → DiffuseColor 覆写 |
|
|
|
|
|
|
| `Shaders/Private/DeferredLightPixelShaders.usf` | L253~L258 | 新增 | 点光源 BGMultColor 色调应用 |
|
|
|
|
|
|
| `Shaders/Private/DeferredLightingCommon.ush` | L166~L172 | 修改 | 阴影合成公式改为 `min(lerp(...), StaticShadowing)` |
|
|
|
|
|
|
| `Shaders/Private/DeferredLightingCommon.ush` | L457~L505 | 新增 | `REDGetShadowTerms` 动态/静态阴影项分离函数 |
|
|
|
|
|
|
| `Shaders/Private/DeferredLightingCommon.ush` | L508~L557 | 新增 | `REDGetShadowColor` 核心阴影着色函数 |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L383~L394 | 新增 | `DynamicShadowShade.Bind` 参数绑定 |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L421~L432 | 新增 | `DynamicShadowShade` 方向光值设置 (0.3/1.0) |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L434~L445 | 新增 | `DynamicShadowShade` 点光源值设置 (1.0) |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L682~L688 | 新增 | `LAYOUT_FIELD(FShaderParameter, DynamicShadowShade)` |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L706~L744 | 新增 | `REDDeferredLightPS` 类 + `IMPLEMENT_GLOBAL_SHADER` |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L950~L961 | 新增 | `bPointLightRED` 排序键 |
|
|
|
|
|
|
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | L2111~L2303 | 新增 | RED 方向光渲染路径(Multiply 混合 + REDDeferredLightPS 调用) |
|