vault backup: 2026-05-03 21:38:46
This commit is contained in:
@@ -54,16 +54,94 @@ BGMultColor 是一个场景级别的全局色调控制系统,通过 `View.BGMu
|
||||
| B | 0~∞ | 蓝色乘数 |
|
||||
| A | 0~1 | 饱和度(0=完全灰度,1=原色) |
|
||||
|
||||
## 完整代码解析
|
||||
|
||||
### Opaque BasePass 应用
|
||||
|
||||
```hlsl
|
||||
// BasePassPixelShader.usf — Opaque 路径
|
||||
// ASW Change : 2020/06/25 11:44:00 Takeshi.N
|
||||
#if USE_BGMULTCOLOR
|
||||
{
|
||||
// 步骤1:颜色乘算(调色)
|
||||
BaseColor *= View.BGMultColor.rgb;
|
||||
|
||||
// 步骤2:计算灰度值(使用 ITU-R BT.601 权重)
|
||||
float Grayscale = dot(BaseColor, float3(0.299f, 0.587f, 0.114f));
|
||||
|
||||
// 步骤3:饱和度控制
|
||||
// A=1.0 保持原色,A=0.0 完全灰度
|
||||
BaseColor = lerp(
|
||||
float3(Grayscale, Grayscale, Grayscale), // 灰度版本
|
||||
BaseColor, // 调色后的版本
|
||||
View.BGMultColor.a); // 饱和度系数
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
### Translucent BasePass 应用
|
||||
|
||||
```hlsl
|
||||
// BasePassPixelShader.usf — Translucent 路径(在最终输出前应用)
|
||||
// ASW Change : 2016/11/04 17:26:48 Takuro.K
|
||||
#if USE_BGMULTCOLOR
|
||||
Out.MRT[0].rgb *= View.BGMultColor.rgb;
|
||||
float Grayscale = dot(Out.MRT[0].rgb, float3(0.299f, 0.587f, 0.114f));
|
||||
Out.MRT[0].rgb = lerp(
|
||||
float3(Grayscale, Grayscale, Grayscale),
|
||||
Out.MRT[0].rgb,
|
||||
View.BGMultColor.a);
|
||||
#endif
|
||||
```
|
||||
|
||||
### Deferred Decal 应用
|
||||
|
||||
```hlsl
|
||||
// DeferredDecal.usf
|
||||
// ASW Change : 2019/10/08 15:37:00 Takeshi.N
|
||||
// 对贴花的 Color 和 BaseColor 都应用 BGMultColor
|
||||
// 确保贴花颜色与场景色调一致
|
||||
#if USE_BGMULTCOLOR
|
||||
// 调制 Color(贴花叠加色)
|
||||
Color.rgb *= View.BGMultColor.rgb;
|
||||
float Grayscale = dot(Color.rgb, float3(0.299f, 0.587f, 0.114f));
|
||||
Color.rgb = lerp(float3(Grayscale, Grayscale, Grayscale), Color.rgb, View.BGMultColor.a);
|
||||
|
||||
// 调制 BaseColor(贴花基色)
|
||||
BaseColor.rgb *= View.BGMultColor.rgb;
|
||||
Grayscale = dot(BaseColor.rgb, float3(0.299f, 0.587f, 0.114f));
|
||||
BaseColor.rgb = lerp(float3(Grayscale, Grayscale, Grayscale), BaseColor.rgb, View.BGMultColor.a);
|
||||
#endif
|
||||
```
|
||||
|
||||
### C++ 端实现
|
||||
|
||||
```cpp
|
||||
// SceneRendering.cpp — 从 REDSceneContext 读取 BGMultColor 写入 ViewUniform
|
||||
// ASW Change : 2016/11/04 Takuro.K
|
||||
if (REDSceneContext)
|
||||
{
|
||||
const UREDSceneContext* pContext = REDSceneContext;
|
||||
ViewUniformShaderParameters.BGMultColor = pContext->BGMultColor;
|
||||
ViewUniformShaderParameters.DisasterPosition = pContext->DisasterPosition;
|
||||
ViewUniformShaderParameters.DisasterWind = pContext->DisasterWind;
|
||||
ViewUniformShaderParameters.DisasterQuake = pContext->DisasterQuake;
|
||||
ViewUniformShaderParameters.DisasterPosition.W = pContext->GameTime;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 关联文档
|
||||
|
||||
- [[REDSceneContext]] — BGMultColor 的数据源
|
||||
- [[自定义后处理]] — 后处理阶段的色彩控制
|
||||
|
||||
## 修改文件列表
|
||||
## 代码修改情况
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | 颜色乘算 + 去饱和 |
|
||||
| `Shaders/Private/DeferredDecal.usf` | 同上 |
|
||||
| `Shaders/Private/DeferredLightPixelShaders.usf` | 点光源颜色调制 |
|
||||
| `Source/Runtime/Renderer/Private/SceneRendering.cpp` | 写入 ViewUniform |
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L869~L878 | 新增 | Opaque 路径 BaseColor BGMultColor 乘算 + 去饱和 |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L1509~L1516 | 新增 | Translucent 路径 MRT[0] BGMultColor 应用 |
|
||||
| `Shaders/Private/DeferredDecal.usf` | L297~L308 | 新增 | Decal Color 和 BaseColor 双重 BGMultColor 应用 |
|
||||
| `Shaders/Private/DeferredLightPixelShaders.usf` | L253~L258 | 新增 | 点光源输出 BGMultColor 调制 |
|
||||
| `Source/Runtime/Renderer/Private/SceneRendering.cpp` | L1717~L1758 | 新增 | 从 `UREDSceneContext` 读取参数写入 ViewUniform |
|
||||
|
||||
@@ -72,15 +72,105 @@ DeviceDepth = lerp(
|
||||
step(PixelDepthOffset, 0)); // PDO <= 0 时使用原始深度
|
||||
```
|
||||
|
||||
## 完整代码解析
|
||||
|
||||
### 阴影专用材质
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2016/11/28 22:27:26 Takuro.K
|
||||
// 阴影专用材质:在 BasePass 中直接丢弃像素
|
||||
// 该网格只参与 Shadow Map 渲染,不产生可见输出
|
||||
// 用于格斗游戏中只需要地面阴影的辅助几何体
|
||||
#if RED_MASKED_SHADOW_ONLY
|
||||
clip(-1); // 参数 < 0 → 丢弃当前像素
|
||||
#endif
|
||||
```
|
||||
|
||||
### 强制 Early-Z
|
||||
|
||||
```hlsl
|
||||
// ASW / Wizcorp Change: 2022/06/03 Maciej.W
|
||||
// 原始条件:!EARLY_Z_PASS_ONLY_MATERIAL_MASKING
|
||||
// 新增条件:&& !EARLY_Z_PASS_FORCED
|
||||
// 当材质标记了 bForcedPrepass 时,跳过 BasePass 中的 Mask clip
|
||||
// 因为深度已经在 PrePass 中确定,无需重复剔除
|
||||
#if !EARLY_Z_PASS_ONLY_MATERIAL_MASKING && !EARLY_Z_PASS_FORCED
|
||||
if (!bEditorWeightedZBuffering)
|
||||
{
|
||||
// Mask clip 逻辑...
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
### X2Multiply 雾效
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2019/10/28 16:51:00 Takeshi.N
|
||||
// X2Multiply 混合模式的雾效处理
|
||||
// X2Multiply 的中性色是 0.5(乘以2后为1.0,不改变目标颜色)
|
||||
// 所以雾效需要将颜色过渡到 0.5 而非 0.0(加法)或 1.0(乘法)
|
||||
#elif MATERIALBLENDING_X2MULTIPLY
|
||||
half3 FoggedColor = lerp(
|
||||
float3(0.5, 0.5, 0.5), // X2Multiply 中性色
|
||||
Color, // 原始颜色
|
||||
Fogging.aaa * Fogging.aaa); // 雾衰减(平方使过渡更平滑)
|
||||
Out.MRT[0] = half4(FoggedColor, Opacity);
|
||||
```
|
||||
|
||||
### 禁用 DEFAULT_LIT 间接光照
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2017/12/14 11:00:00 Takeshi.N
|
||||
// 对 DEFAULT_LIT + Deferred 路径禁用预计算间接光照
|
||||
// 因为在 RED 管线中,BaseColor 被用于阴影颜色而非 PBR 漫反射
|
||||
// 间接光照会干扰卡通阴影效果
|
||||
#if MATERIAL_SHADINGMODEL_DEFAULT_LIT && !(FORWARD_SHADING || TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING)
|
||||
// 跳过 GetPrecomputedIndirectLightingAndSkyLight 及相关计算
|
||||
#else
|
||||
// 原始间接光照逻辑
|
||||
float3 DiffuseIndirectLighting;
|
||||
float3 SubsurfaceIndirectLighting;
|
||||
GetPrecomputedIndirectLightingAndSkyLight(...);
|
||||
DiffuseColor += (DiffuseIndirectLighting * DiffuseColorForIndirect + ...) * AOMultiBounce(...);
|
||||
#endif
|
||||
```
|
||||
|
||||
### C++ 端实现
|
||||
|
||||
```cpp
|
||||
// BasePassRendering.cpp — X2Multiply BlendState
|
||||
// ASW Change Y.Kawakami 2020/05/21
|
||||
case BLEND_X2Multiply:
|
||||
// X2Multiply 使用与 Multiply 相同的 BlendState
|
||||
break;
|
||||
```
|
||||
|
||||
```cpp
|
||||
// BasePassRendering.cpp — ForcedPrepass
|
||||
// ASW / Wizcorp Change: 2022/06/03 Maciej.W
|
||||
const bool bEnforceMaskedEarlyPass =
|
||||
Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel)->IsForcedPrepass()
|
||||
&& EarlyZPassMode != DDM_None;
|
||||
// 强制该材质走 Early-Z PrePass,减少 OverDraw
|
||||
```
|
||||
|
||||
## 关联文档
|
||||
|
||||
- [[自定义材质属性]] — `bForcedPrepass` 和 `BLEND_X2Multiply`
|
||||
- [[RED自定义数据通道]] — BasePass 中 CustomData 的写入
|
||||
|
||||
## 修改文件列表
|
||||
## 代码修改情况
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | 阴影 Only、X2Multiply 雾效 |
|
||||
| `Source/Runtime/Renderer/Private/BasePassRendering.cpp` | 强制 PrePass、X2Multiply BlendState |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | PDO 修复 |
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L772~L776 | 新增 | `RED_MASKED_SHADOW_ONLY` 阴影专用材质 `clip(-1)` |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L850~L854 | 修改 | Early-Z 条件添加 `!EARLY_Z_PASS_FORCED` |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L1137~L1163 | 修改 | DEFAULT_LIT Deferred 路径禁用预计算间接光 |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L1291~L1296 | 修改 | Emissive 声明前移(与 CustomData 配合) |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L1433~L1438 | 新增 | `MATERIALBLENDING_X2MULTIPLY` 雾效处理 |
|
||||
| `Source/Runtime/Renderer/Private/BasePassRendering.cpp` | L200~L216 | 新增 | `BLEND_X2Multiply` case 分支 |
|
||||
| `Source/Runtime/Renderer/Private/BasePassRendering.cpp` | L288~L309 | 新增 | `bEnforceMaskedEarlyPass` 强制 PrePass 判断 |
|
||||
| `Source/Runtime/Renderer/Private/BasePassRendering.cpp` | L1068~L1087 | 新增 | Shader Define 注入(`USE_RED_CUSTOM_DATA`/`USE_BGMULTCOLOR`/`USES_ORTHO_BLEND`等) |
|
||||
| `Source/Runtime/Renderer/Private/BasePassRendering.cpp` | L1633~L1694 | 新增 | X2Multiply/AdditiveForUI BlendState 设置 |
|
||||
| `Source/Runtime/Renderer/Private/DepthRendering.cpp` | L925~L1061 | 新增 | ForcedPrepass 深度渲染逻辑 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2584~L2587 | 新增 | PixelDepthOffset 修复 |
|
||||
|
||||
@@ -52,14 +52,53 @@ OutColor.a = 1.f;
|
||||
|
||||
防止降采样过程中 Alpha 通道携带的 CustomData 信息影响后续后处理。
|
||||
|
||||
## 完整代码解析
|
||||
|
||||
### PostProcessDownsample Alpha 修复
|
||||
|
||||
```hlsl
|
||||
// PostProcessDownsample.usf
|
||||
// 强制 Alpha 为 1.0,防止 CustomData 中的 OutlineID 信息
|
||||
// 在降采样过程中泄漏到后续后处理 Pass
|
||||
OutColor.rgb = max(float3(0,0,0), OutColor.rgb);
|
||||
OutColor.a = 1.f; // <-- ASW 新增
|
||||
```
|
||||
|
||||
### C++ 端实现
|
||||
|
||||
```cpp
|
||||
// SceneRenderTargets.cpp — GBufferD 清除色修改
|
||||
// ASW Change : 2016/11/09 Takuro.K
|
||||
// 将 GBufferD 清除色改为 (0,0,0,0)
|
||||
// 确保未写入 CustomData 的像素 OutlineID=0、PointLight DiffuseColor=黑色
|
||||
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(
|
||||
BufferSize, BufferFormat,
|
||||
FClearValueBinding(FLinearColor(0, 0, 0, 0)), // <-- 清除色改为全0
|
||||
TexCreate_SRGB,
|
||||
TexCreate_RenderTargetable | TexCreate_ShaderResource, false));
|
||||
```
|
||||
|
||||
```cpp
|
||||
// SceneRenderTargets.cpp — Specular GBuffer 格式
|
||||
// ASW Change : 2017/11/21 Takuro.K
|
||||
// 非 PS5 平台降低 Specular 精度到 PF_A8(8位)
|
||||
// 卡通渲染中 Specular 通常阶梯化,不需要高精度
|
||||
#if defined(PLATFORM_PS5) && !PLATFORM_PS5
|
||||
const EPixelFormat SpecularGBufferFormat = PF_A8;
|
||||
#endif
|
||||
```
|
||||
|
||||
## 关联文档
|
||||
|
||||
- [[RED自定义数据通道]] — GBufferD 的数据写入方
|
||||
- [[自定义后处理]] — 读取 GBufferD 数据
|
||||
|
||||
## 修改文件列表
|
||||
## 代码修改情况
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Source/Runtime/Renderer/Private/SceneRenderTargets.cpp` | GBufferD 清除色、Specular 格式 |
|
||||
| `Shaders/Private/PostProcessDownsample.usf` | Alpha 强制为 1.0 |
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp` | L737 | 修改 | Normal GBuffer 格式(已禁用) |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp` | L1257~L1268 | 修改 | Specular GBuffer → `PF_A8`(非PS5) |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp` | L1271~L1284 | 修改 | GBufferD 清除色 → `(0,0,0,0)` |
|
||||
| `Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp` | L1364~L1380 | 修改 | GBuffer 格式相关调整 |
|
||||
| `Shaders/Private/PostProcessDownsample.usf` | L63 | 新增 | `OutColor.a = 1.f` 强制 Alpha 为 1 |
|
||||
|
||||
@@ -119,12 +119,157 @@ RED 自定义数据通道是 ARC 引擎中一个巧妙的 GBuffer 复用方案
|
||||
- [[自定义后处理]] — CharaGlow 读取 OutlineID 通道
|
||||
- [[GBuffer修改]] — GBufferD 清除色等相关修改
|
||||
|
||||
## 修改文件列表
|
||||
## 完整代码解析
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/Definitions.usf` | 新增 `USE_RED_CUSTOM_DATA` 宏定义 |
|
||||
| `Shaders/Private/BasePassCommon.ush` | 扩展 `WRITES_CUSTOMDATA_TO_GBUFFER` |
|
||||
| `Shaders/Private/ShadingModelsMaterial.ush` | UNLIT/DEFAULT_LIT 写入 CustomData |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | SubsurfaceColor 重定义逻辑 |
|
||||
| `Shaders/Private/DeferredShadingCommon.ush` | GBufferD 写入 |
|
||||
### Definitions.usf — 宏定义
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2020/01/14 20:19:00 Takeshi.N
|
||||
// 点光源自定义数据宏:启用时将 Emissive 写入 GBufferD 作为点光源 DiffuseColor
|
||||
#ifndef USE_RED_CUSTOM_DATA_POINTLIGHT
|
||||
#define USE_RED_CUSTOM_DATA_POINTLIGHT 0
|
||||
#endif
|
||||
|
||||
// ASW Change : 2018/06/20 14:00:00 Takeshi.N
|
||||
// 基础自定义数据宏:启用时将 SubsurfaceData.b(OutlineID)写入 GBufferD
|
||||
// 默认值跟随点光源模式,即点光源模式开启时基础模式也自动开启
|
||||
#ifndef USE_RED_CUSTOM_DATA
|
||||
#define USE_RED_CUSTOM_DATA USE_RED_CUSTOM_DATA_POINTLIGHT
|
||||
#endif
|
||||
```
|
||||
|
||||
### BasePassCommon.ush — WRITES_CUSTOMDATA_TO_GBUFFER 扩展
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2018/06/20 14:00:00 Takeshi.N
|
||||
// 将 USE_RED_CUSTOM_DATA 加入 CustomData 写入条件
|
||||
// 原始条件仅包含 SSS 相关 ShadingModel,现在 RED 自定义数据也可触发 GBufferD 写入
|
||||
#define WRITES_CUSTOMDATA_TO_GBUFFER (USES_GBUFFER && ( \
|
||||
MATERIAL_SHADINGMODEL_SUBSURFACE || \
|
||||
MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || \
|
||||
MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || \
|
||||
MATERIAL_SHADINGMODEL_CLEAR_COAT || \
|
||||
MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || \
|
||||
MATERIAL_SHADINGMODEL_HAIR || \
|
||||
MATERIAL_SHADINGMODEL_CLOTH || \
|
||||
MATERIAL_SHADINGMODEL_EYE || \
|
||||
USE_RED_CUSTOM_DATA )) // ← 新增条件
|
||||
```
|
||||
|
||||
### ShadingModelsMaterial.ush — UNLIT/DEFAULT_LIT CustomData 填充
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2018/06/20 14:00:00 Takeshi.N
|
||||
// 为 UNLIT 着色模型注入自定义数据
|
||||
// 正常情况下 UNLIT 不写入 GBufferD,但 RED 系统需要存储轮廓线 ID
|
||||
#if MATERIAL_SHADINGMODEL_UNLIT
|
||||
GBuffer.ShadingModelID = SHADINGMODELID_UNLIT;
|
||||
#if USE_RED_CUSTOM_DATA
|
||||
// SubsurfaceColor.rgb = 阴影基色或清零(取决于模式)
|
||||
// SubsurfaceProfile = OutlineID 或 0.0
|
||||
GBuffer.CustomData = float4(SubsurfaceColor, SubsurfaceProfile);
|
||||
#endif
|
||||
|
||||
// ASW Change : 2018/06/20 14:00:00 Takeshi.N
|
||||
// 为 DEFAULT_LIT 着色模型注入自定义数据
|
||||
// DEFAULT_LIT 原本也不写入 CustomData,现在复用该通道
|
||||
#elif MATERIAL_SHADINGMODEL_DEFAULT_LIT
|
||||
GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
|
||||
#if USE_RED_CUSTOM_DATA
|
||||
GBuffer.CustomData = float4(SubsurfaceColor, SubsurfaceProfile);
|
||||
#endif
|
||||
#endif
|
||||
```
|
||||
|
||||
### BasePassPixelShader.usf — SubsurfaceColor 重定义
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2020/01/14 20:19:00 Takeshi.N (点光源模式)
|
||||
// ASW Change : 2018/06/20 14:00:00 Takeshi.N (基础模式)
|
||||
// 在 Base Pass 中重新定义 SubsurfaceColor 的含义
|
||||
// 这段代码在正式写入 GBuffer 之前执行,覆写材质系统原本的 SubsurfaceColor
|
||||
#if USE_RED_CUSTOM_DATA
|
||||
{
|
||||
#if USE_RED_CUSTOM_DATA_POINTLIGHT
|
||||
// 点光源模式:
|
||||
// 将材质的 Emissive 输出作为点光源的 DiffuseColor(阴影基色)
|
||||
// 这意味着美术可以在材质编辑器中通过 Emissive 通道控制点光源阴影颜色
|
||||
SubsurfaceColor = Emissive; // Emissive → DiffuseColor
|
||||
SubsurfaceProfile = 0.0; // 点光源模式不使用 OutlineID
|
||||
// 注意:此处覆写后原始 Emissive 功能失效
|
||||
// 如需自发光效果需通过其他方式实现
|
||||
#else
|
||||
// 基础模式:
|
||||
// 从材质的 SubsurfaceData 读取数据,B 通道存储 OutlineID
|
||||
// OutlineID 用于后续轮廓线渲染中区分不同物体的轮廓线参数
|
||||
float4 SubsurfaceData = GetMaterialSubsurfaceData(PixelMaterialInputs);
|
||||
SubsurfaceColor = float3(0, 0, 0); // RGB 清零(基础模式不存储颜色)
|
||||
SubsurfaceProfile = SubsurfaceData.b; // B 通道 = OutlineID
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
### DeferredShadingCommon.ush — GBufferD 写入
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2018/06/20 14:00:00 Takeshi.N
|
||||
// 在 EncodeGBuffer 函数中,将 CustomData 直接写入 GBufferD
|
||||
// 原始逻辑中只有 SSS 相关 ShadingModel 才会写入 GBufferD
|
||||
// 现在通过 USE_RED_CUSTOM_DATA 宏,UNLIT 和 DEFAULT_LIT 也可以写入
|
||||
|
||||
// 原始代码根据 ShadingModelID 分支写入:
|
||||
// case SHADINGMODELID_SUBSURFACE: OutGBufferD = ...
|
||||
// case SHADINGMODELID_SUBSURFACE_PROFILE: OutGBufferD = ...
|
||||
|
||||
// RED 修改:在所有分支之后追加无条件覆写
|
||||
#if USE_RED_CUSTOM_DATA
|
||||
// 无论 ShadingModelID 是什么,都将 CustomData 写入 GBufferD
|
||||
// 这确保了 UNLIT/DEFAULT_LIT 材质的数据也能正确输出
|
||||
OutGBufferD = GBuffer.CustomData;
|
||||
#endif
|
||||
|
||||
// 注意:这个覆写意味着如果同时启用了 RED_CUSTOM_DATA 和 SSS 材质,
|
||||
// SSS 的 CustomData 也会被覆写为 RED 的数据
|
||||
// 这是设计上的权衡——RED 系统下不支持 SSS 材质
|
||||
```
|
||||
|
||||
### 数据流总结
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 材质编辑器 │
|
||||
│ 基础模式:SubsurfaceData.b → OutlineID │
|
||||
│ 点光源模式:Emissive → DiffuseColor │
|
||||
└─────────────────┬───────────────────────────────────────────────┘
|
||||
│ BasePassPixelShader.usf
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ SubsurfaceColor / SubsurfaceProfile 重新赋值 │
|
||||
│ 点光源模式:SubsurfaceColor = Emissive │
|
||||
│ 基础模式:SubsurfaceProfile = SubsurfaceData.b │
|
||||
└─────────────────┬───────────────────────────────────────────────┘
|
||||
│ ShadingModelsMaterial.ush
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ GBuffer.CustomData = float4(SubsurfaceColor, SubsurfaceProfile) │
|
||||
└─────────────────┬───────────────────────────────────────────────┘
|
||||
│ DeferredShadingCommon.ush
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ OutGBufferD = GBuffer.CustomData │
|
||||
│ → GBufferD.rgb = DiffuseColor(点光源阴影基色) │
|
||||
│ → GBufferD.b = OutlineID(轮廓线 ID) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 代码修改情况
|
||||
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/Definitions.usf` | L65~L76 | 新增 | `USE_RED_CUSTOM_DATA_POINTLIGHT` 和 `USE_RED_CUSTOM_DATA` 宏定义 |
|
||||
| `Shaders/Private/BasePassCommon.ush` | L28~L34 | 修改 | `TRANSLUCENCY_NEEDS_BASEPASS_FOGGING` 添加 `!USES_SCREEN_ALIGNED_MESH` |
|
||||
| `Shaders/Private/BasePassCommon.ush` | L51~L57 | 修改 | `WRITES_CUSTOMDATA_TO_GBUFFER` 添加 `USE_RED_CUSTOM_DATA` 条件 |
|
||||
| `Shaders/Private/ShadingModelsMaterial.ush` | L35~L53 | 新增 | `UNLIT` 和 `DEFAULT_LIT` 的 CustomData 写入逻辑 |
|
||||
| `Shaders/Private/BasePassPixelShader.usf` | L928~L943 | 新增 | SubsurfaceColor 重定义(OutlineID / PointLight DiffuseColor) |
|
||||
| `Shaders/Private/DeferredShadingCommon.ush` | L403~L409 | 修改 | Unlit 路径 GBufferD 写入 `GBuffer.CustomData` |
|
||||
|
||||
@@ -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 调用) |
|
||||
|
||||
@@ -42,13 +42,45 @@ struct FRayTracingPipelineStateInitializer
|
||||
|
||||
新增 `bApplyAdditionalState` 参数,控制是否在设置管线状态时应用额外的平台特化状态。
|
||||
|
||||
## 完整代码解析
|
||||
|
||||
```hlsl
|
||||
// RayTracingDeferredReflections.usf
|
||||
// 仅缩进格式修复(去掉一级缩进),无功能性变更
|
||||
// 不影响运行时行为
|
||||
```
|
||||
|
||||
```cpp
|
||||
// RHI 模块 — PSO 部分编译标记
|
||||
struct FRayTracingPipelineStateInitializer
|
||||
{
|
||||
// ASW 新增:允许部分编译
|
||||
// 不需要等待所有 Hit Shader 就绪即可使用基础管线
|
||||
// 用于减少首次光线追踪渲染时的卡顿
|
||||
bool bPartial;
|
||||
|
||||
// 基础 PSO,用于派生新的 PSO
|
||||
// 派生 PSO 只需要编译差异部分
|
||||
FRayTracingPipelineState* BasePipeline;
|
||||
};
|
||||
|
||||
// SetGraphicsPipelineState 扩展
|
||||
// ASW 新增 bApplyAdditionalState 参数
|
||||
// 控制是否在设置管线状态时应用平台特化的额外状态
|
||||
void RHISetGraphicsPipelineState(
|
||||
FGraphicsPipelineStateInitializer& Initializer,
|
||||
bool bApplyAdditionalState = true // <-- 新增参数
|
||||
);
|
||||
```
|
||||
|
||||
## 关联文档
|
||||
|
||||
- [[D3D12RHI]] — D3D12 层面的 PSO 异步创建改进
|
||||
|
||||
## 修改文件列表
|
||||
## 代码修改情况
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/RayTracing/RayTracingDeferredReflections.usf` | 格式修复 |
|
||||
| `Source/Runtime/RHI/` | `bPartial`、`bApplyAdditionalState` |
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/RayTracing/RayTracingDeferredReflections.usf` | L109~L121 | 格式 | 缩进调整(无功能变更) |
|
||||
| `Source/Runtime/RHI/` | — | 修改 | `FRayTracingPipelineStateInitializer` 新增 `bPartial`、`BasePipeline` |
|
||||
| `Source/Runtime/RHI/` | — | 修改 | `SetGraphicsPipelineState` 新增 `bApplyAdditionalState` 参数 |
|
||||
|
||||
@@ -43,12 +43,62 @@ void VertexFactoryUpdateLocalPositionScale(
|
||||
|
||||
`MP_LocalPositionScale`(float3)通过材质图控制。参见 [[自定义材质属性]]。
|
||||
|
||||
## 修改文件列表
|
||||
## 完整代码解析
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/LocalVertexFactory.ush` | 新增缩放函数 |
|
||||
| `Shaders/Private/GpuSkinVertexFactory.ush` | 同上 |
|
||||
| `Shaders/Private/LandscapeVertexFactory.ush` | 同上 |
|
||||
| `Shaders/Private/MeshParticleVertexFactory.ush` | 同上 |
|
||||
| 所有 Particle VertexFactory | 同上 |
|
||||
### LocalVertexFactory.ush — 缩放函数定义
|
||||
|
||||
```hlsl
|
||||
// LocalVertexFactory.ush — 缩放函数定义
|
||||
// ASW Change : 2016/06/29 17:05:39 Takuro.K
|
||||
#if USES_LOCAL_POSITION_SCALE
|
||||
void VertexFactoryUpdateLocalPositionScale(
|
||||
inout FVertexFactoryInput Input, // 顶点输入(可修改)
|
||||
inout FVertexFactoryIntermediates Intermediates, // 中间数据
|
||||
float3 scale) // 缩放系数 (x, y, z)
|
||||
{
|
||||
// 直接在局部空间缩放顶点位置
|
||||
// 在 WorldTransform 之前应用,所以效果与 Actor Scale 类似
|
||||
// 但由材质图控制,可以做动画
|
||||
Input.Position.xyz *= scale;
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
### BasePassVertexShader.usf — 调用流程
|
||||
|
||||
```hlsl
|
||||
// BasePassVertexShader.usf — 调用流程
|
||||
// ASW Change : 2016/06/29 17:05:39 Takuro.K
|
||||
#if USES_LOCAL_POSITION_SCALE
|
||||
{
|
||||
// 1. 从材质图获取缩放系数
|
||||
// 2. 应用到顶点的局部坐标
|
||||
VertexFactoryUpdateLocalPositionScale(Input, VFIntermediates,
|
||||
GetMaterialLocalPositionScale(VertexParameters));
|
||||
|
||||
// 3. 重新计算世界坐标(因为局部坐标已改变)
|
||||
WorldPositionExcludingWPO = VertexFactoryGetWorldPosition(Input, VFIntermediates);
|
||||
WorldPosition = WorldPositionExcludingWPO;
|
||||
|
||||
// 4. 重新获取切线空间和材质参数
|
||||
TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates);
|
||||
VertexParameters = GetMaterialVertexParameters(
|
||||
Input, VFIntermediates, WorldPosition.xyz, TangentToLocal);
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
## 代码修改情况
|
||||
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | L64~L76 | 新增 | 调用 `VertexFactoryUpdateLocalPositionScale` + 重算世界坐标 |
|
||||
| `Shaders/Private/LocalVertexFactory.ush` | L1171~L1179 | 新增 | `VertexFactoryUpdateLocalPositionScale` 函数(`Input.Position.xyz *= scale`) |
|
||||
| `Shaders/Private/GpuSkinVertexFactory.ush` | L822~L830 | 新增 | 同上(GPU 蒙皮版本) |
|
||||
| `Shaders/Private/LandscapeVertexFactory.ush` | L948~L958 | 新增 | 同上(Landscape 版本) |
|
||||
| `Shaders/Private/MeshParticleVertexFactory.ush` | L728~L736 | 新增 | 同上(MeshParticle 版本) |
|
||||
| `Shaders/Private/ParticleSpriteVertexFactory.ush` | L684~L691 | 新增 | 同上(ParticleSprite 版本) |
|
||||
| `Shaders/Private/ParticleGPUSpriteVertexFactory.ush` | L698~L706 | 新增 | 同上(ParticleGPUSprite 版本) |
|
||||
| `Shaders/Private/ParticleBeamTrailVertexFactory.ush` | L246~L253 | 新增 | 同上(ParticleBeamTrail 版本) |
|
||||
| `Shaders/Private/VectorFieldVisualizationVertexFactory.ush` | L202~L210 | 新增 | 同上(VectorField 版本) |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2263~L2268 | 新增 | `GetMaterialLocalPositionScale` 材质访问函数 |
|
||||
|
||||
@@ -55,11 +55,77 @@ rating: ⭐
|
||||
|
||||
材质标记 `bScreenAlignedMesh` 启用此模式。
|
||||
|
||||
## 修改文件列表
|
||||
## 完整代码解析
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | 屏幕空间变换逻辑 |
|
||||
| `Shaders/Private/DepthOnlyVertexShader.usf` | 同上 |
|
||||
| `Shaders/Private/HitProxyVertexShader.usf` | 同上 |
|
||||
| `Shaders/Private/DebugViewModeVertexShader.usf` | 同上 |
|
||||
### BasePassVertexShader.usf — 屏幕对齐变换
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2016/05/16 13:56:33 Takuro.K
|
||||
// 屏幕对齐网格:将3D网格直接投影到屏幕空间
|
||||
#if USES_SCREEN_ALIGNED_MESH
|
||||
{
|
||||
// 获取 LocalToWorld 矩阵(区分实例化和非实例化模式)
|
||||
#if PARTICLE_MESH_INSTANCED
|
||||
float4x4 LocalToWorld = VertexParameters.InstanceLocalToWorld;
|
||||
#else
|
||||
float3x3 LocalToWorld = GetLocalToWorld3x3(VertexParameters.PrimitiveId);
|
||||
#endif
|
||||
|
||||
// 从 LocalToWorld 矩阵的对角元素获取翻转方向
|
||||
// 这样网格在镜像 Transform 下仍然正确显示
|
||||
#if PARTICLE_MESH_INSTANCED
|
||||
float2 flip = sign( float2( Input.Transform1.x, LocalToWorld[1][1] ) );
|
||||
#else
|
||||
float2 flip = sign( float2( LocalToWorld[0][0], LocalToWorld[1][1] ) );
|
||||
#endif
|
||||
|
||||
// 使用顶点的 X 和 Z 坐标作为屏幕坐标(不是 XY!)
|
||||
// 这是因为网格在 DCC 中通常面向 Z 轴建模
|
||||
float2 p = Input.Position.xz * flip;
|
||||
|
||||
// 从材质图获取偏移和缩放参数
|
||||
float3 offset = GetMaterialScreenAlignedMeshOffset(VertexParameters);
|
||||
float3 scale = GetMaterialScreenAlignedMeshScale(VertexParameters);
|
||||
|
||||
// 基于 1280x720 参考分辨率计算屏幕坐标
|
||||
// NDC 范围 [-1, 1],所以 /640 和 /360 将像素单位转为 NDC
|
||||
float2 ScreenPos = p.xy * scale.xy;
|
||||
ScreenPos.x += offset.x / 640.0f; // X 偏移(向右为正)
|
||||
ScreenPos.y += -offset.y / 360.0f; // Y 偏移(向上为正,NDC Y 轴反转)
|
||||
|
||||
// WorldPositionOffset 也可以叠加微调
|
||||
ScreenPos.xy += GetMaterialWorldPositionOffset(VertexParameters).xy;
|
||||
|
||||
// 深度设为接近远裁面,确保不遮挡 3D 场景
|
||||
const float z = 1.0f - 0.00001f;
|
||||
|
||||
// 清零世界坐标(屏幕空间渲染不需要)
|
||||
WorldPosition = 0;
|
||||
// 直接设置裁剪空间输出(w=1 表示无透视除法)
|
||||
Output.Position = float4( ScreenPos, z, 1 );
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
### BasePassCommon.ush — 禁用雾效
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2017/01/30 18:00:41 Takuro.K
|
||||
// 屏幕对齐网格不需要雾效(它们是屏幕空间元素)
|
||||
#define TRANSLUCENCY_NEEDS_BASEPASS_FOGGING (
|
||||
MATERIAL_ENABLE_TRANSLUCENCY_FOGGING &&
|
||||
MATERIALBLENDING_ANY_TRANSLUCENT &&
|
||||
!MATERIAL_USES_SCENE_COLOR_COPY &&
|
||||
!USES_SCREEN_ALIGNED_MESH) // <-- 新增条件
|
||||
```
|
||||
|
||||
## 代码修改情况
|
||||
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | L118~L155 | 新增 | 屏幕对齐网格变换逻辑(1280x720基准/深度设置/WorldPosition清零) |
|
||||
| `Shaders/Private/BasePassCommon.ush` | L28~L34 | 修改 | `TRANSLUCENCY_NEEDS_BASEPASS_FOGGING` 禁用 ScreenAlignedMesh 雾效 |
|
||||
| `Shaders/Private/DepthOnlyVertexShader.usf` | — | 新增 | 同上变换逻辑(DepthOnly Pass) |
|
||||
| `Shaders/Private/HitProxyVertexShader.usf` | — | 新增 | 同上(HitProxy Pass) |
|
||||
| `Shaders/Private/DebugViewModeVertexShader.usf` | — | 新增 | 同上(DebugViewMode Pass) |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2243~L2252 | 新增 | `GetMaterialScreenAlignedMeshOffset/Scale` 材质访问函数 |
|
||||
|
||||
@@ -40,10 +40,47 @@ rating: ⭐
|
||||
|
||||
`MP_ScreenSpaceDepthOffset`(float)通过材质图控制。参见 [[自定义材质属性]]。
|
||||
|
||||
## 修改文件列表
|
||||
## 完整代码解析
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | 深度偏移逻辑 |
|
||||
| `Shaders/Private/DepthOnlyVertexShader.usf` | 同上 |
|
||||
| `Shaders/Private/PositionOnlyDepthVertexShader.usf` | 同上 |
|
||||
### Common.ush — 深度偏移方向宏定义
|
||||
|
||||
```hlsl
|
||||
// Common.ush — 深度偏移方向宏定义
|
||||
// ASW Change : 2016/06/07 15:20:36 Takuro.K
|
||||
#if USES_SCREEN_SPACE_DEPTH_OFFSET
|
||||
// 根据深度缓冲方向确定偏移符号
|
||||
// 反向 Z(近=1,远=0):偏移为负 = 向远处推
|
||||
// 正向 Z(近=0,远=1):偏移为正 = 向远处推
|
||||
#if HAS_INVERTED_Z_BUFFER
|
||||
#define DEPTH_OFFSET_SIGN -1.0f
|
||||
#else
|
||||
#define DEPTH_OFFSET_SIGN 1.0f
|
||||
#endif
|
||||
#endif
|
||||
```
|
||||
|
||||
### BasePassVertexShader.usf — 应用深度偏移
|
||||
|
||||
```hlsl
|
||||
// BasePassVertexShader.usf — 应用深度偏移
|
||||
// ASW Change : 2016/06/07 15:20:36 Takuro.K
|
||||
#if USES_SCREEN_SPACE_DEPTH_OFFSET
|
||||
{
|
||||
// 从材质图获取偏移值,乘以方向符号
|
||||
// 正值 = 向远处推(在屏幕上看起来更远)
|
||||
// 负值 = 向近处拉
|
||||
Output.Position.z += GetMaterialScreenSpaceDepthOffset(VertexParameters)
|
||||
* DEPTH_OFFSET_SIGN;
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
## 代码修改情况
|
||||
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/Common.ush` | L1803~L1810 | 新增 | `DEPTH_OFFSET_SIGN` 宏定义(根据 Z-buffer 方向) |
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | L158~L163 | 新增 | `Output.Position.z += offset * DEPTH_OFFSET_SIGN` |
|
||||
| `Shaders/Private/DepthOnlyVertexShader.usf` | — | 新增 | 同上深度偏移应用 |
|
||||
| `Shaders/Private/PositionOnlyDepthVertexShader.usf` | L49~L59 | 新增 | 同上 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2255~L2260 | 新增 | `GetMaterialScreenSpaceDepthOffset` 材质访问函数 |
|
||||
|
||||
@@ -123,14 +123,183 @@ float GetMaterialOrthoBlendWeight(FMaterialVertexParameters Parameters)
|
||||
- [[屏幕对齐网格]] — 另一种屏幕空间变换方案
|
||||
- [[局部位置缩放]] — 局部空间的顶点变换
|
||||
|
||||
## 修改文件列表
|
||||
## 完整代码解析
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Shaders/Private/Common.ush` | 新增 `GetOrthoBlendPosition` / `GetOrthoBlendPosition2` |
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | 调用正交混合 |
|
||||
| `Shaders/Private/DepthOnlyVertexShader.usf` | 调用正交混合 |
|
||||
| `Shaders/Private/PositionOnlyDepthVertexShader.usf` | 调用正交混合 |
|
||||
| `Shaders/Private/HitProxyVertexShader.usf` | 调用正交混合 |
|
||||
| `Shaders/Private/DebugViewModeVertexShader.usf` | 调用正交混合 |
|
||||
| 所有 VertexFactory `.ush` | 提供 ObjWorldPosition |
|
||||
### Common.ush — V1:X轴正交混合
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2016/03/29 11:30:55 Takuro.K
|
||||
// V1:X轴正交混合
|
||||
// 在透视投影的X轴坐标和正交投影的X轴坐标之间做 lerp
|
||||
// weight 来自材质属性 MP_OrthoBlendWeight
|
||||
// ResolvedView.OrthoBlendParameter 是全局混合强度
|
||||
float4 GetOrthoBlendPosition( float4 WorldPosition, float4x4 ViewProjectionMatrix, float weight )
|
||||
{
|
||||
#if USES_ORTHO_BLEND_POSITION
|
||||
float4 ScreenPosition = mul(WorldPosition, ViewProjectionMatrix);
|
||||
// 用正交投影矩阵的X行点乘世界坐标,得到正交投影下的X坐标
|
||||
float OrthoScreenPositionX = dot(ResolvedView.OrthoViewProjectionX, WorldPosition);
|
||||
|
||||
// 在透视X和正交X之间混合
|
||||
// 注意乘以 ScreenPosition.w 是为了从 NDC 空间转回裁剪空间
|
||||
ScreenPosition.x = lerp(
|
||||
ScreenPosition.x, // 透视X
|
||||
OrthoScreenPositionX * ScreenPosition.w, // 正交X(转回裁剪空间)
|
||||
weight * ResolvedView.OrthoBlendParameter ); // 混合权重
|
||||
|
||||
return ScreenPosition;
|
||||
#else
|
||||
return mul(WorldPosition, ViewProjectionMatrix);
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
### Common.ush — V2:全透视校正("Purse correction")
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2019/01/11 13:53:00 Takeshi.N
|
||||
// V2:全透视校正("Purse correction")
|
||||
// 原理:将所有顶点投影到与物体中心等距的平面上
|
||||
// 消除前后肢体因透视导致的大小差异
|
||||
float4 GetOrthoBlendPosition2( float4 WorldPosition, float4x4 ViewProjectionMatrix,
|
||||
float weight, float3 ObjWorldPosition )
|
||||
{
|
||||
#if USES_ORTHO_BLEND_POSITION2
|
||||
|
||||
#if PARTICLE_FACTORY && !PARTICLE_MESH_FACTORY
|
||||
// 非网格粒子不做透视校正,直接返回标准投影
|
||||
return mul(WorldPosition, ViewProjectionMatrix);
|
||||
#else
|
||||
// 保存原始裁剪空间位置(用于最终 lerp)
|
||||
float4 ClipSpacePositionOrigin = mul(WorldPosition, ViewProjectionMatrix);
|
||||
|
||||
// 计算顶点相对于物体中心的偏移
|
||||
float3 offset = WorldPosition.xyz - ObjWorldPosition.xyz;
|
||||
|
||||
// 物体中心到相机的距离(沿视线方向的投影距离)
|
||||
float dist = abs(dot(
|
||||
ObjWorldPosition.xyz - ResolvedView.WorldCameraOrigin.xyz,
|
||||
ResolvedView.ViewForward.xyz));
|
||||
|
||||
// 在视线方向上,距离相机 dist 处的点
|
||||
float3 origin = ResolvedView.WorldCameraOrigin.xyz
|
||||
+ ResolvedView.ViewForward.xyz * dist;
|
||||
|
||||
// 关键步骤:将顶点XY"拍平"到与物体中心等距的平面
|
||||
// 这样所有顶点在相机方向上的距离相同,消除透视缩放差异
|
||||
WorldPosition.xy = origin.xy + offset.xy;
|
||||
float4 ClipSpacePosition = mul(WorldPosition, ViewProjectionMatrix);
|
||||
|
||||
// X轴补偿:物体中心可能不在视线正前方
|
||||
// 需要补偿因"拍平"导致的X轴偏移
|
||||
float4x1 VPM_X = float4x1( ViewProjectionMatrix._11_21_31_41 );
|
||||
float x1 = mul(float4(origin, 1), VPM_X); // "拍平"参考点的X
|
||||
float x2 = mul(float4(ObjWorldPosition, 1), VPM_X); // 物体中心的X
|
||||
ClipSpacePosition.x += ClipSpacePosition.w * (x2 - x1) / dist;
|
||||
|
||||
// 根据全局参数和材质权重,在原始位置和校正位置之间混合
|
||||
// step(0.01, weight) 确保 weight 接近0时完全不应用校正
|
||||
return lerp( ClipSpacePositionOrigin, ClipSpacePosition,
|
||||
ResolvedView.OrthoBlendParameter * step(0.01, weight) );
|
||||
#endif
|
||||
|
||||
#else
|
||||
return mul(WorldPosition, ViewProjectionMatrix);
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
### BasePassVertexShader.usf — 调用逻辑
|
||||
|
||||
```hlsl
|
||||
// BasePassVertexShader.usf 中的调用逻辑
|
||||
// 按优先级选择:V2 > V1 > 原始投影
|
||||
#if USES_ORTHO_BLEND_POSITION2
|
||||
// V2 透视校正:传入物体世界坐标作为参考点
|
||||
ClipSpacePosition = GetOrthoBlendPosition2(
|
||||
RasterizedWorldPosition,
|
||||
ResolvedView.TranslatedWorldToClip,
|
||||
GetMaterialOrthoBlendWeight( VertexParameters ), // 材质图中设置的权重
|
||||
GetActorWorldPosition(VertexParameters.PrimitiveId) // 物体世界坐标
|
||||
);
|
||||
#elif USES_ORTHO_BLEND_POSITION
|
||||
// V1 简单X轴混合
|
||||
ClipSpacePosition = GetOrthoBlendPosition(
|
||||
RasterizedWorldPosition,
|
||||
ResolvedView.TranslatedWorldToClip,
|
||||
GetMaterialOrthoBlendWeight( VertexParameters )
|
||||
);
|
||||
#else
|
||||
// 原始透视投影
|
||||
ClipSpacePosition = INVARIANT(mul(RasterizedWorldPosition, ResolvedView.TranslatedWorldToClip));
|
||||
#endif
|
||||
```
|
||||
|
||||
### C++ 端实现
|
||||
|
||||
```cpp
|
||||
// SceneRendering.cpp — 正交投影混合参数计算
|
||||
// ASW Change : 2016/03/29 Takuro.K
|
||||
|
||||
// 计算正交投影矩阵的 X 行(用于 Shader 中 dot 计算正交 X 坐标)
|
||||
static FVector4 CalcOrthoBlendParameter(
|
||||
const FViewMatrices& ViewMatrices,
|
||||
const FMatrix& EffectiveTranslatedViewMatrix)
|
||||
{
|
||||
const FVector2D FOVTheta = ViewMatrices.ComputeHalfFieldOfViewPerAxis();
|
||||
float distance = ViewMatrices.GetOrthoBlendBaseDistance();
|
||||
float w = distance * FMath::Tan(FOVTheta.X);
|
||||
float h = distance * FMath::Tan(FOVTheta.Y);
|
||||
|
||||
// 构建正交投影矩阵,提取 X 行
|
||||
const FMatrix orthoMat = FOrthoMatrix(w, h, 0, 1);
|
||||
const FMatrix ViewOrthoMatrix = EffectiveTranslatedViewMatrix * orthoMat;
|
||||
return FVector4(
|
||||
ViewOrthoMatrix.M[0][0],
|
||||
ViewOrthoMatrix.M[1][0],
|
||||
ViewOrthoMatrix.M[2][0],
|
||||
ViewOrthoMatrix.M[3][0]);
|
||||
}
|
||||
|
||||
// 计算混合权重(基于相机朝向的衰减)
|
||||
static float CalcOrthoBlendWeight(
|
||||
const FViewMatrices& ViewMatrices,
|
||||
const FMatrix& EffectiveTranslatedViewMatrix)
|
||||
{
|
||||
float weight = ViewMatrices.GetOrthoBlendWeight();
|
||||
// 相机正面朝向时权重最大,侧面时衰减
|
||||
float face = ViewMatrices.GetOrthoBlendBaseRot()
|
||||
.RotateVector(FVector(1, 0, 0)).X;
|
||||
if (weight < 1.0f)
|
||||
{
|
||||
static const float THRESHOLD_MIN = 0.995f;
|
||||
static const float RANGE = 1.0f - THRESHOLD_MIN;
|
||||
face = FMath::Max((face - THRESHOLD_MIN) / RANGE, 0.0f);
|
||||
weight *= face * face; // 平方衰减
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// SceneRendering.cpp — 写入 ViewUniformShaderParameters
|
||||
ViewUniformShaderParameters.OrthoViewProjectionX =
|
||||
CalcOrthoBlendParameter(ViewMatrices, TranslatedViewMatrix);
|
||||
ViewUniformShaderParameters.OrthoBlendParameter =
|
||||
CalcOrthoBlendWeight(ViewMatrices, TranslatedViewMatrix);
|
||||
```
|
||||
|
||||
## 代码修改情况
|
||||
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/Common.ush` | L1739~L1758 | 新增 | `GetOrthoBlendPosition` V1 X轴正交混合函数 |
|
||||
| `Shaders/Private/Common.ush` | L1761~L1800 | 新增 | `GetOrthoBlendPosition2` V2 全透视校正函数 |
|
||||
| `Shaders/Private/BasePassVertexShader.usf` | L94~L114 | 新增 | V2/V1 投影分支调用逻辑 |
|
||||
| `Shaders/Private/DepthOnlyVertexShader.usf` | L152~L220 | 新增 | 同上(DepthOnly Pass) |
|
||||
| `Shaders/Private/PositionOnlyDepthVertexShader.usf` | L49~L59 | 新增 | 同上(PositionOnlyDepth) |
|
||||
| `Shaders/Private/HitProxyVertexShader.usf` | L147~L169 | 新增 | 同上(HitProxy Pass) |
|
||||
| `Shaders/Private/DebugViewModeVertexShader.usf` | L162~L219 | 新增 | 同上(DebugViewMode Pass) |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2235~L2240 | 新增 | `GetMaterialOrthoBlendWeight` 材质访问函数 |
|
||||
| `Source/Runtime/Renderer/Private/SceneRendering.cpp` | L1014~L1067 | 新增 | `CalcOrthoBlendParameter` / `CalcOrthoBlendWeight` 函数 |
|
||||
| `Source/Runtime/Renderer/Private/SceneRendering.cpp` | L1717~L1758 | 新增 | 写入 `ViewUniformShaderParameters` OrthoBlend 参数 |
|
||||
|
||||
@@ -81,10 +81,87 @@ SortKey |= bPointLightRED ? (1 << PointLightSortBit) : 0;
|
||||
- [[RED阴影系统]] — 核心阴影着色逻辑
|
||||
- [[RED自定义数据通道]] — 点光源 CustomData 的来源
|
||||
|
||||
## 修改文件列表
|
||||
## 完整代码解析
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | `REDDeferredLightPS`、排序、Decal |
|
||||
| `Shaders/Private/DeferredLightPixelShaders.usf` | `REDDirectionalPixelMain`、CustomData 覆写 |
|
||||
| `Shaders/Private/DeferredLightingCommon.ush` | 阴影合成修改 |
|
||||
> Shader 侧的完整代码解析(`REDDirectionalPixelMain`、`REDGetShadowTerms`、`REDGetShadowColor`)请参见 [[RED阴影系统#完整代码解析]]。本节仅补充 C++ 端的结构说明。
|
||||
|
||||
### LightRendering.cpp — REDDeferredLightPS 类结构
|
||||
|
||||
```cpp
|
||||
// ASW Change : 2016/10/12 21:35:18 Takuro.K
|
||||
// 继承自标准 FDeferredLightPS,新增 DynamicShadowShade 参数绑定
|
||||
class REDDeferredLightPS : public FDeferredLightPS
|
||||
{
|
||||
DECLARE_SHADER_TYPE(REDDeferredLightPS, Global);
|
||||
|
||||
// Shader 参数声明
|
||||
FShaderParameter DynamicShadowShadeParam;
|
||||
|
||||
// 构造函数中绑定参数
|
||||
REDDeferredLightPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
||||
: FDeferredLightPS(Initializer)
|
||||
{
|
||||
DynamicShadowShadeParam.Bind(
|
||||
Initializer.ParameterMap, TEXT("DynamicShadowShade"));
|
||||
}
|
||||
|
||||
// SetParameters 中传入光源的 DynamicShadowShade 值
|
||||
void SetParameters(FRHICommandList& RHICmdList,
|
||||
const FSceneView& View,
|
||||
const FLightSceneInfo* LightSceneInfo)
|
||||
{
|
||||
FDeferredLightPS::SetParameters(RHICmdList, View, LightSceneInfo);
|
||||
|
||||
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
||||
// 从光源信息获取 DynamicShadowShade 值并设置到 GPU
|
||||
SetShaderValue(RHICmdList, ShaderRHI,
|
||||
DynamicShadowShadeParam,
|
||||
LightSceneInfo->DynamicShadowShade);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### LightRendering.cpp — 点光源排序
|
||||
|
||||
```cpp
|
||||
// ASW Change : 2019/02/05 20:37:00 Takeshi.N
|
||||
// 确保点光源在方向光之后渲染,让方向光阴影着色先完成
|
||||
// bPointLightRED 标志位用于区分 RED 系统的点光源
|
||||
uint32 SortKey = 0;
|
||||
SortKey |= bDirectionalLight ? 0 : (1 << DirectionalLightSortBit);
|
||||
SortKey |= bPointLightRED ? (1 << PointLightSortBit) : 0;
|
||||
|
||||
// 排序结果:DirectionalLight(RED) → PointLight(RED) → 其他光源
|
||||
```
|
||||
|
||||
### LightRendering.cpp — RED_CUSTOM_LIGHTING 条件分派
|
||||
|
||||
```cpp
|
||||
// 根据 RED_CUSTOM_LIGHTING 宏决定使用标准光照还是 RED 光照
|
||||
#if RED_CUSTOM_LIGHTING
|
||||
if (bUseREDLighting)
|
||||
{
|
||||
// 使用 REDDeferredLightPS 渲染方向光
|
||||
TShaderMapRef<REDDeferredLightPS> PixelShader(View.ShaderMap);
|
||||
// ...
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// 标准 UE4 Deferred Light 路径
|
||||
TShaderMapRef<FDeferredLightPS> PixelShader(View.ShaderMap);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 代码修改情况
|
||||
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | — | 新增 | `REDDeferredLightPS` 类(继承 `FDeferredLightPS`) |
|
||||
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | — | 新增 | `DynamicShadowShade` Shader 参数绑定 |
|
||||
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | — | 修改 | 点光源排序键 `bPointLightRED`(方向光后渲染) |
|
||||
| `Source/Runtime/Renderer/Private/LightRendering.cpp` | — | 修改 | Decal Emissive → 正常光照贡献 |
|
||||
| `Shaders/Private/DeferredLightPixelShaders.usf` | L109~L145 | 新增 | `REDDirectionalPixelMain` 入口(详见 [[RED阴影系统]]) |
|
||||
| `Shaders/Private/DeferredLightPixelShaders.usf` | L236~L239 | 新增 | CustomData → DiffuseColor 覆写 |
|
||||
| `Shaders/Private/DeferredLightingCommon.ush` | L457~L557 | 新增 | `REDGetShadowTerms` + `REDGetShadowColor`(详见 [[RED阴影系统]]) |
|
||||
|
||||
@@ -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` |
|
||||
|
||||
@@ -86,20 +86,77 @@ if (Material.bForcedPrepass)
|
||||
|
||||
新增 `REDMaterialInstanceDynamic` 类(`REDMaterialInstanceDynamic.h/.cpp`),扩展了标准 `UMaterialInstanceDynamic`,可能用于运行时的卡通渲染材质参数控制。
|
||||
|
||||
## 完整代码解析
|
||||
|
||||
### MaterialTemplate.ush — 新增材质属性访问函数
|
||||
|
||||
```hlsl
|
||||
// MaterialTemplate.ush — 新增材质属性访问函数
|
||||
// ASW Change : 2016/03/29 ~ 2016/06/29 Takuro.K
|
||||
|
||||
// 正交投影混合权重 (float)
|
||||
// 材质图中连接到此 Pin 的表达式会在编译时替换 %s
|
||||
float GetMaterialOrthoBlendWeight(FMaterialVertexParameters Parameters)
|
||||
{
|
||||
%s; // 由 HLSLMaterialTranslator 填充
|
||||
}
|
||||
|
||||
// 屏幕对齐网格偏移 (float3, 像素单位, 基于1280x720)
|
||||
float3 GetMaterialScreenAlignedMeshOffset(FMaterialVertexParameters Parameters)
|
||||
{
|
||||
%s;
|
||||
}
|
||||
|
||||
// 屏幕对齐网格缩放 (float3)
|
||||
float3 GetMaterialScreenAlignedMeshScale(FMaterialVertexParameters Parameters)
|
||||
{
|
||||
%s;
|
||||
}
|
||||
|
||||
// 屏幕空间深度偏移 (float, 正值向远推)
|
||||
float GetMaterialScreenSpaceDepthOffset(FMaterialVertexParameters Parameters)
|
||||
{
|
||||
%s;
|
||||
}
|
||||
|
||||
// 局部位置缩放 (float3, 在WorldTransform前应用)
|
||||
float3 GetMaterialLocalPositionScale(FMaterialVertexParameters Parameters)
|
||||
{
|
||||
%s;
|
||||
}
|
||||
```
|
||||
|
||||
### PixelDepthOffset 修复
|
||||
|
||||
```hlsl
|
||||
// ASW Change : 2020/10/29 Takeshi.N
|
||||
// 修复 PC 平台 PixelDepthOffset 为 0 或负值时的噪声问题
|
||||
// 当 PDO <= 0 时,直接使用原始 SvPosition.z 而非计算值
|
||||
DeviceDepth = lerp(
|
||||
DeviceDepth, // PDO > 0:使用计算后的深度
|
||||
MaterialParameters.SvPosition.z, // PDO <= 0:使用原始深度
|
||||
step(PixelDepthOffset, 0) // step 函数:PDO<=0 返回 1
|
||||
);
|
||||
```
|
||||
|
||||
## 关联文档
|
||||
|
||||
- [[正交投影混合]] — 使用 `MP_OrthoBlendWeight`
|
||||
- [[屏幕对齐网格]] — 使用 `MP_ScreenAlignedMeshOffset/Scale`
|
||||
- [[BasePass修改]] — `bForcedPrepass` 的影响
|
||||
|
||||
## 修改文件列表
|
||||
## 代码修改情况
|
||||
|
||||
| 文件 | 修改类型 |
|
||||
|------|---------|
|
||||
| `Source/Runtime/Engine/Public/SceneTypes.h` | 新增 `MP_*` 枚举 |
|
||||
| `Source/Runtime/Engine/Classes/Materials/Material.h` | 新增 `bScreenAlignedMesh`、`bForcedPrepass` |
|
||||
| `Source/Runtime/Engine/Classes/Materials/REDMaterialInstanceDynamic.h` | **新增** |
|
||||
| `Source/Runtime/Engine/Private/Materials/REDMaterialInstanceDynamic.cpp` | **新增** |
|
||||
| `Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.cpp` | 编译支持 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | 新增访问函数 |
|
||||
| `Source/Editor/MaterialEditor/` | 编辑器 UI 支持 |
|
||||
| 文件路径 | 行号 | 修改类型 | 修改内容 |
|
||||
|---------|------|---------|---------|
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2235~L2240 | 新增 | `GetMaterialOrthoBlendWeight` 函数 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2243~L2252 | 新增 | `GetMaterialScreenAlignedMeshOffset/Scale` 函数 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2255~L2260 | 新增 | `GetMaterialScreenSpaceDepthOffset` 函数 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2263~L2268 | 新增 | `GetMaterialLocalPositionScale` 函数 |
|
||||
| `Shaders/Private/MaterialTemplate.ush` | L2584~L2587 | 新增 | PixelDepthOffset ≤ 0 时使用原始深度 |
|
||||
| `Source/Runtime/Engine/Public/SceneTypes.h` | — | 新增 | `MP_OrthoBlendWeight` 等枚举值 |
|
||||
| `Source/Runtime/Engine/Classes/Materials/Material.h` | — | 新增 | `bScreenAlignedMesh`、`bForcedPrepass` 标记 |
|
||||
| `Source/Runtime/Engine/Classes/Materials/REDMaterialInstanceDynamic.h` | 全文 | **新增文件** | 自定义 MaterialInstanceDynamic |
|
||||
| `Source/Runtime/Engine/Private/Materials/REDMaterialInstanceDynamic.cpp` | 全文 | **新增文件** | 实现 |
|
||||
| `Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.cpp` | — | 修改 | 新属性编译支持 |
|
||||
| `Source/Editor/MaterialEditor/` | — | 修改 | 编辑器 UI 支持 |
|
||||
|
||||
Reference in New Issue
Block a user