vault backup: 2026-05-03 21:38:46

This commit is contained in:
2026-05-03 21:38:46 +08:00
parent 83502d0874
commit 0a81d4ee33
34 changed files with 2442 additions and 845 deletions

View File

@@ -117,10 +117,280 @@ ScreenSpaceData.GBuffer.DiffuseColor.rgb = ScreenSpaceData.GBuffer.CustomData.rg
- [[自定义光照Pass]] — REDDeferredLightPS 的 C++ 绑定
- [[BGMultColor全局色调]] — 场景全局色调叠加
## 修改文件列表
## 完整代码解析
| 文件 | 修改类型 |
|------|---------|
| `Shaders/Private/DeferredLightPixelShaders.usf` | 新增 `REDDirectionalPixelMain` |
| `Shaders/Private/DeferredLightingCommon.ush` | 新增 `REDGetShadowTerms``REDGetShadowColor` |
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | 新增 `REDDeferredLightPS`、点光排序 |
### 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
// 混合模式改为 MultiplyDestColor × SourceColor
// 标准 UE4 用 AdditiveRED 用 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 调用) |