vault backup: 2026-05-03 21:38:46
This commit is contained in:
@@ -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)
|
||||
// 混合模式改为 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 调用) |
|
||||
|
||||
Reference in New Issue
Block a user