vault backup: 2026-05-03 21:38:46
This commit is contained in:
@@ -121,16 +121,359 @@ float CharaGlowArea;
|
||||
FLinearColor CharaGlowColor;
|
||||
```
|
||||
|
||||
## 完整代码解析
|
||||
|
||||
### REDPostProcess.usf 完整着色器注解
|
||||
|
||||
#### 辅助函数
|
||||
|
||||
```hlsl
|
||||
// 灰度计算(ITU-R BT.601 标准权重)
|
||||
float GetGrayscale(float3 Color)
|
||||
{
|
||||
return dot(Color, float3(0.299f, 0.587f, 0.114f));
|
||||
}
|
||||
|
||||
// 饱和度插值:在灰度和原色之间按 Saturation 系数过渡
|
||||
float3 LerpSaturation(float3 Color, float Saturation)
|
||||
{
|
||||
float Gray = GetGrayscale(Color);
|
||||
return lerp(float3(Gray, Gray, Gray), Color, Saturation);
|
||||
}
|
||||
```
|
||||
|
||||
#### 高斯核权重(7 权重,13-tap 对称核)
|
||||
|
||||
```hlsl
|
||||
// ColorSampleWeight — 用于降采样和模糊的高斯权重
|
||||
// 对称分布:中心权重最大,两侧递减
|
||||
// 权重值(半侧,index 0=中心):
|
||||
// [0] = 0.3990 (中心)
|
||||
// [1] = 0.2420
|
||||
// [2] = 0.0540
|
||||
// [3] = 0.0044
|
||||
// [4] = 0.0001 (接近零)
|
||||
// 合计 ≈ 1.0(归一化)
|
||||
static const float ColorSampleWeight[7] = {
|
||||
0.0044f, 0.0540f, 0.2420f, 0.3990f, 0.2420f, 0.0540f, 0.0044f
|
||||
};
|
||||
```
|
||||
|
||||
#### DownSamplingPS — 降采样
|
||||
|
||||
```hlsl
|
||||
// 4x4 区域降采样为 1 像素(用于创建 1/4 分辨率 RT)
|
||||
// 采样模式:2x2 双线性采样点,每点覆盖 2x2 像素
|
||||
void DownSamplingPS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
float2 UVOffset = 0.5f * InvSize; // 半像素偏移
|
||||
|
||||
// 4 次双线性采样取平均
|
||||
OutColor = Texture2DSample(SceneColorTexture, SceneColorSampler, InUV + float2(-UVOffset.x, -UVOffset.y));
|
||||
OutColor += Texture2DSample(SceneColorTexture, SceneColorSampler, InUV + float2( UVOffset.x, -UVOffset.y));
|
||||
OutColor += Texture2DSample(SceneColorTexture, SceneColorSampler, InUV + float2(-UVOffset.x, UVOffset.y));
|
||||
OutColor += Texture2DSample(SceneColorTexture, SceneColorSampler, InUV + float2( UVOffset.x, UVOffset.y));
|
||||
OutColor *= 0.25f;
|
||||
}
|
||||
```
|
||||
|
||||
#### BlurVerticalPS / BlurHorizonPS — 分离高斯模糊
|
||||
|
||||
```hlsl
|
||||
// 13-tap 分离高斯模糊(垂直方向)
|
||||
// 使用 ColorSampleWeight 权重,两侧各 6 个采样点 + 中心 1 个
|
||||
void BlurVerticalPS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
OutColor = float4(0, 0, 0, 0);
|
||||
|
||||
// 遍历 -6 到 +6 的偏移量
|
||||
for (int i = -6; i <= 6; i++)
|
||||
{
|
||||
float2 SampleUV = InUV + float2(0, i * InvSize.y); // 垂直偏移
|
||||
float Weight = ColorSampleWeight[abs(i)]; // 对称权重
|
||||
OutColor += Texture2DSample(SceneColorTexture, SceneColorSampler, SampleUV) * Weight;
|
||||
}
|
||||
}
|
||||
|
||||
// 13-tap 分离高斯模糊(水平方向)
|
||||
// 结构与垂直相同,仅偏移方向改为水平
|
||||
void BlurHorizonPS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
OutColor = float4(0, 0, 0, 0);
|
||||
|
||||
for (int i = -6; i <= 6; i++)
|
||||
{
|
||||
float2 SampleUV = InUV + float2(i * InvSize.x, 0); // 水平偏移
|
||||
float Weight = ColorSampleWeight[abs(i)];
|
||||
OutColor += Texture2DSample(SceneColorTexture, SceneColorSampler, SampleUV) * Weight;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### DiffusionFilterPS — 基于亮度的辉光提取
|
||||
|
||||
```hlsl
|
||||
// Diffusion Filter:从场景中提取高亮区域用于后续模糊
|
||||
// 步骤:
|
||||
// 1. 采样场景颜色
|
||||
// 2. 计算亮度 → 幂次调整 → 阈值裁剪
|
||||
// 3. 输出 = 原始颜色 × 亮度遮罩
|
||||
void DiffusionFilterPS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
float4 SceneColor = Texture2DSample(SceneColorTexture, SceneColorSampler, InUV);
|
||||
|
||||
// 亮度计算
|
||||
float Luminance = GetGrayscale(SceneColor.rgb);
|
||||
|
||||
// 幂次映射:LuminancePow 越大,只有越亮的区域才会被保留
|
||||
float LuminanceMask = pow(Luminance, DiffusionFilterLuminancePow);
|
||||
|
||||
// 阈值裁剪:低于阈值的区域完全去除
|
||||
LuminanceMask = saturate(LuminanceMask - DiffusionFilterLuminanceThreshold);
|
||||
|
||||
// 输出带亮度遮罩的颜色
|
||||
OutColor = float4(SceneColor.rgb * LuminanceMask, 1.0f);
|
||||
}
|
||||
```
|
||||
|
||||
#### DiffusionFilter2PS — Screen 混合 + Power
|
||||
|
||||
```hlsl
|
||||
// Diffusion Filter 2:将模糊后的辉光以 Screen 模式叠加回场景
|
||||
// Screen blend: Result = 1 - (1-A)(1-B)
|
||||
// 然后应用 Power 调整对比度
|
||||
void DiffusionFilter2PS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
// 采样原始场景
|
||||
float4 SceneColor = Texture2DSample(SceneColorTexture, SceneColorSampler, InUV);
|
||||
|
||||
// 采样模糊后的辉光
|
||||
float4 BlurColor = Texture2DSample(BlurTexture, BlurSampler, InUV);
|
||||
|
||||
// Screen 混合
|
||||
float3 BlendResult = 1.0f - (1.0f - SceneColor.rgb) * (1.0f - BlurColor.rgb);
|
||||
|
||||
// Power 调整(DiffusionFilterPower 控制辉光强度曲线)
|
||||
BlendResult = pow(BlendResult, DiffusionFilterPower);
|
||||
|
||||
OutColor = float4(BlendResult, 1.0f);
|
||||
}
|
||||
```
|
||||
|
||||
#### SoftFocus — 柔焦
|
||||
|
||||
```hlsl
|
||||
// Soft Focus:场景与模糊版本的混合 + 饱和度调节
|
||||
// 实现类似相机柔焦镜片的效果
|
||||
void SoftFocus(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
float4 SceneColor = Texture2DSample(SceneColorTexture, SceneColorSampler, InUV);
|
||||
float4 BlurColor = Texture2DSample(BlurTexture, BlurSampler, InUV);
|
||||
|
||||
// 在清晰和模糊之间按 SoftFocusBlend 系数混合
|
||||
float3 Result = lerp(SceneColor.rgb, BlurColor.rgb, SoftFocusBlend);
|
||||
|
||||
// 饱和度调节
|
||||
Result = LerpSaturation(Result, SoftFocusSaturation);
|
||||
|
||||
OutColor = float4(Result, 1.0f);
|
||||
}
|
||||
```
|
||||
|
||||
#### Glow — 辉光
|
||||
|
||||
```hlsl
|
||||
// Glow:基于亮度阈值的辉光效果
|
||||
// 与 DiffusionFilter 类似但更简单,直接以 Screen 混合叠加
|
||||
void Glow(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
float4 SceneColor = Texture2DSample(SceneColorTexture, SceneColorSampler, InUV);
|
||||
float4 BlurColor = Texture2DSample(BlurTexture, BlurSampler, InUV);
|
||||
|
||||
// Screen 混合辉光
|
||||
float3 Result = 1.0f - (1.0f - SceneColor.rgb) * (1.0f - BlurColor.rgb * GlowIntensity);
|
||||
|
||||
OutColor = float4(Result, 1.0f);
|
||||
}
|
||||
```
|
||||
|
||||
#### CharaGlowPS — 角色辉光模糊
|
||||
|
||||
```hlsl
|
||||
// 角色辉光 Pass 1:可变半径 Box Blur
|
||||
// 从 GBufferD.b 读取辉光遮罩(由 OutlineID 编码)
|
||||
// 以可变半径进行 Box Blur 扩散辉光范围
|
||||
void CharaGlowPS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
float Sum = 0;
|
||||
float Count = 0;
|
||||
|
||||
// 从 CharaGlowArea 计算模糊半径(像素数)
|
||||
int Radius = (int)CharaGlowArea;
|
||||
|
||||
// 双重循环 Box Blur
|
||||
for (int y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
for (int x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
float2 SampleUV = InUV + float2(x, y) * InvSize;
|
||||
|
||||
// 采样 GBufferD.b 通道作为辉光遮罩
|
||||
float Mask = Texture2DSample(GBufferDTexture, GBufferDSampler, SampleUV).b;
|
||||
|
||||
Sum += Mask;
|
||||
Count += 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 归一化
|
||||
OutColor = float4(Sum / Count, 0, 0, 1);
|
||||
}
|
||||
```
|
||||
|
||||
#### CharaGlowCompPS — 角色辉光合成
|
||||
|
||||
```hlsl
|
||||
// 角色辉光 Pass 2:将模糊后的辉光遮罩与辉光颜色合成
|
||||
// 叠加到场景颜色上
|
||||
void CharaGlowCompPS(
|
||||
float4 Position : SV_POSITION,
|
||||
float2 InUV : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0)
|
||||
{
|
||||
// 采样场景颜色
|
||||
float4 SceneColor = Texture2DSample(SceneColorTexture, SceneColorSampler, InUV);
|
||||
|
||||
// 采样模糊后的辉光遮罩
|
||||
float GlowMask = Texture2DSample(CharaGlowTexture, CharaGlowSampler, InUV).r;
|
||||
|
||||
// 减去原始遮罩(只保留扩散出去的边缘部分)
|
||||
float OriginalMask = Texture2DSample(GBufferDTexture, GBufferDSampler, InUV).b;
|
||||
GlowMask = saturate(GlowMask - OriginalMask);
|
||||
|
||||
// 以 CharaGlowColor 叠加辉光
|
||||
float3 Result = SceneColor.rgb + GlowMask * CharaGlowColor.rgb * CharaGlowColor.a;
|
||||
|
||||
OutColor = float4(Result, 1.0f);
|
||||
}
|
||||
```
|
||||
|
||||
### C++ 端实现
|
||||
|
||||
```cpp
|
||||
// REDPostProcess.h — 后处理 Pass 类型枚举
|
||||
enum REDPostProcess_Type {
|
||||
EREDPostProcess_DownSample, // 降采样
|
||||
EREDPostProcess_BlurH, // 水平高斯模糊
|
||||
EREDPostProcess_BlurV, // 垂直高斯模糊
|
||||
};
|
||||
|
||||
// 基础后处理 Pass(降采样 + 模糊)
|
||||
class FRCPassREDPostProcess : public TRenderingCompositePassBase<1, 1>
|
||||
{
|
||||
REDPostProcess_Type Type;
|
||||
bool bToHalf; // 是否降采样到半分辨率
|
||||
void RenderDownSamplingPass(FRenderingCompositePassContext& Context);
|
||||
void RenderBlurHPass(FRenderingCompositePassContext& Context);
|
||||
void RenderBlurVPass(FRenderingCompositePassContext& Context);
|
||||
};
|
||||
|
||||
// Diffusion Filter Pass(亮度提取 + Screen 混合)
|
||||
class FRCPassREDPostProcess_DiffusionFilter : public TRenderingCompositePassBase<2, 1> { ... };
|
||||
|
||||
// Diffusion Filter 2 Pass(Power + 阈值 + 可选 CharaGlow 合成)
|
||||
class FRCPassREDPostProcess_DiffusionFilter2 : public TRenderingCompositePassBase<4, 1> { ... };
|
||||
|
||||
// CharaGlow Pass(可变半径 BoxBlur on GBufferD.b)
|
||||
class FRCPassREDPostProcess_CharaGlow : public TRenderingCompositePassBase<1, 1> { ... };
|
||||
```
|
||||
|
||||
```cpp
|
||||
// PostProcessing.cpp — 后处理管线插入
|
||||
// CVar 控制插入位置
|
||||
static TAutoConsoleVariable<int32> CVarREDPostprocessAfterTranslucency(
|
||||
TEXT("r.REDPostprocessAfterTranslucency"),
|
||||
// 0: SeparateTranslucency 之前
|
||||
// 1: SeparateTranslucency 之后
|
||||
// 2: Bloom 之后
|
||||
);
|
||||
|
||||
// AddREDPostProcess — 构建后处理图
|
||||
static void AddREDPostProcess(FPostprocessContext& Context)
|
||||
{
|
||||
float pow = Context.View.FinalPostProcessSettings.DiffusionFilterLuminancePow;
|
||||
// 创建降采样 → 水平模糊 → 垂直模糊 → DiffusionFilter2 节点链
|
||||
FRenderingCompositePass* NodeDownSample = new FRCPassREDPostProcess(EREDPostProcess_DownSample, true);
|
||||
FRenderingCompositePass* NodeBlurH = new FRCPassREDPostProcess(EREDPostProcess_BlurH, false);
|
||||
FRenderingCompositePass* NodeBlurV = new FRCPassREDPostProcess(EREDPostProcess_BlurV, false);
|
||||
|
||||
// 可选:CharaGlow(角色辉光)
|
||||
float area = Context.View.FinalPostProcessSettings.CharaGlowArea;
|
||||
if (area > 0) {
|
||||
FLinearColor color = Context.View.FinalPostProcessSettings.CharaGlowColor;
|
||||
FRenderingCompositePass* NodeGlow = new FRCPassREDPostProcess_CharaGlow(color, area);
|
||||
// ... 连接到图
|
||||
}
|
||||
|
||||
// 最终 DiffusionFilter2 节点
|
||||
float threshold = Context.View.FinalPostProcessSettings.DiffusionFilterLuminanceThreshold;
|
||||
FRenderingCompositePass* NodeFinal = new FRCPassREDPostProcess_DiffusionFilter2(pow, threshold, bWithGlow);
|
||||
}
|
||||
```
|
||||
|
||||
## 关联文档
|
||||
|
||||
- [[RED自定义数据通道]] — CharaGlow 读取 GBufferD.b 通道
|
||||
- [[BGMultColor全局色调]] — 另一个全局色彩控制系统
|
||||
|
||||
## 修改文件列表
|
||||
## 代码修改情况
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/REDPostProcess.usf` | **新增** — 完整后处理着色器 |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/REDPostProcess.h` | **新增** — C++ 后处理 Pass |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/REDPostProcess.cpp` | **新增** — C++ 实现 |
|
||||
| `Source/Runtime/Engine/Classes/Engine/Scene.h` | 新增 PostProcess 参数 |
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/REDPostProcess.usf` | 全文 (473行) | **新增文件** | 完整自定义后处理着色器 |
|
||||
| ↳ | L49~L57 | — | `PostProcessVS` 标准顶点着色器 |
|
||||
| ↳ | L61~L86 | — | `PostProcessBlurVS` 高斯模糊顶点着色器(预计算7个采样点) |
|
||||
| ↳ | L96~L105 | — | `ColorSampleWeight[7]` 高斯权重表 |
|
||||
| ↳ | L117~L129 | — | `GetGrayscale` / `LerpSaturation` 辅助函数 |
|
||||
| ↳ | L134~L137 | — | `DownSamplingPS` 降采样 |
|
||||
| ↳ | L142~L191 | — | `BlurVerticalPS` 垂直高斯模糊(13-tap) |
|
||||
| ↳ | L196~L246 | — | `BlurHorizonPS` 水平高斯模糊(13-tap) |
|
||||
| ↳ | L251~L278 | — | `DiffusionFilterPS` 扩散滤镜(亮度提取 + max 混合) |
|
||||
| ↳ | L283~L318 | — | `DiffusionFilter2PS` 扩散滤镜2(Screen 混合 + CharaGlow 合成) |
|
||||
| ↳ | L323~L350 | — | `DiffusionFilter2WithOutCharaGlowPS` 不含辉光版本 |
|
||||
| ↳ | L355~L376 | — | `DiffusionFilter2SepiaPS` 棕褐色变体 |
|
||||
| ↳ | L383~L393 | — | `SoftFocus` 柔焦效果 |
|
||||
| ↳ | L400~L430 | — | `Glow` 辉光(亮度阈值 + Screen 混合) |
|
||||
| ↳ | L437~L455 | — | `CharaGlowPS` 角色辉光(可变半径 BoxBlur on GBufferD.b) |
|
||||
| ↳ | L461~L470 | — | `CharaGlowCompPS` 辉光合成(叠加到场景 + mask) |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/REDPostProcess.h` | 全文 (298行) | **新增文件** | 后处理 Pass 类声明(4个 Pass 类 + 枚举) |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/REDPostProcess.cpp` | 全文 (1735行) | **新增文件** | 后处理 Pass 实现(Shader 绑定/参数设置/RT 管理) |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp` | L100~L129 | 新增 | `#include "REDPostProcess.h"` + `CVarREDPostprocessAfterTranslucency` CVar |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp` | L224~L661 | 新增 | `AddREDPostProcess` 完整后处理图构建函数 (~438行) |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp` | L669~L681 | 修改 | 根据 CVar 在管线中插入 RED 后处理 |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp` | L852~L908 | 新增 | CharaGlow 独立模式插入逻辑 |
|
||||
| `Source/Runtime/Engine/Classes/Engine/Scene.h` | — | 修改 | 新增 `DiffusionFilterLuminancePow/Threshold`、`CharaGlowArea/Color` |
|
||||
|
||||
Reference in New Issue
Block a user