*Last update 2025.05.16*
*持續踩坑,不定時更新文件*
*主要為記錄哪些東西要去修改的筆記,並非某特定渲染效果的教學*
*歡迎留下feedback*
# 前置作業: 取得Source Code
要先取得 Unreal Github 權限;需要連動 Epic Games 以及 Github 帳號。
申請方法與連結: https://www.unrealengine.com/en-US/ue-on-github
有了權限以後就可以 Clone 或 Fork `Unreal Engine Source Code` 來用。
# 備註
* 有關 Visual Studio 編譯
* 如果沒有修改 `.h` `.cpp` 檔案,只有修改 `.ush` `.usf` 檔案,直接開專案重新Compile Shaders 即可。
* 本篇的環境版本
* Unreal Engine version: fork from Epic's 5.5 branch
* IDE: Visual Studio 2022 17.13.6
* 硬體建議
* 請務必把 Source code 裝在 SSD,不然完整Build都要8-9小時起跳
* CPU 越好 Build 越快
* 當然RAM也不要太小,建議至少40G以上,32G有時候會爆 (個人觀察RAM用量大概在25-33G左右) ~~48G雙通道CP值真不錯~~
* ~~貴,從來都不是它的缺點。而是你的缺點。~~

# 相關檔案
### C++ header(.h) and source (.cpp)
| file | purpose |
|:---------------------------------------------- |:-------------------------------------------------------------------------- |
| **EngineTypes.h** | 主要用於定義引擎相關設置, `Material Shading Model` Enum在此處擴充 |
| **SceneTypes.h** | 主要用於定義渲染相關Enum等 ,在此擴充Material Parameters |
| **Material.h** | 主要用於Material系統相關設置, 需要在此新增MSM UPROPERTY |
| **Material.cpp** | 主要用於Material系統相關設置,e.g.設定各個MSM要用哪些MP |
| **ShaderMaterial.h** | 主要用於定義輔助的Struct, functions以及參數;需要在此新增輔助參數給新的MSM |
| **MaterialExpressionMakeMaterialAttributes.h** | 擴充Material Attributes |
| **PixelInspectorResult.h** | 擴充Pixel Inspector工具中的 Shading model 定義 |
| **PixelInspectorResult.cpp** | 擴充Pixel Inspector工具中的 Shading model 定義 |
| **ShaderGenerationUtil.cpp** | 定義新的 Shading model 所需要使用的 Gbuffer slots |
| **HLSLMaterialTranslator.cpp** | 修改材質轉譯成HLSL相關設定, 包含 Shading model, GBuffer slot 相關 |
| **MaterialAttributeDefinitionMap.cpp** | 擴充 Material Attributes |
| **MaterialHLSLEmitter.cpp** | 擴充 HLSL 編譯器的 Shading model 定義 |
| **MaterialEditor.cpp** | 擴充 Material Pin 參數類型定義 |
| **MaterialGraph.cpp** | 擴充 Material Graph 介面的 Material parameters 相關定義 |
| **MaterialShader.cpp** | 擴充Material Attributes |
| **MaterialExpressions.cpp** | 擴充MaterialExpressions, Material Attributes |
| **MaterialCachedData.cpp** | 修改 Material Expression 相關設定 |
| **ShaderMaterialDerivedHelpers.cpp** | 修改 GBuffer 相關使用設定 |
| **GBufferInfo.h** | 擴充 GBuffer slot 相關內容 |
| **GBufferInfo.cpp** | 擴充 GBuffer slot 相關內容 |
| **SceneRendering.cpp** | 擴充 GBuffer slot 相關內容 |
| **SceneTextureParameters.h** | 擴充 GBuffer slot 相關內容 |
| **SceneTextureParameters.cpp** | 擴充 GBuffer slot 相關內容 |
| **SceneTexturesConfig.h** | 擴充 GBuffer slot 相關內容 |
| SceneTexturesConfig.cpp | 擴充 GBuffer slot 相關內容 |
| **SceneTextures.h** | 擴充 GBuffer slot 相關內容 |
| **SceneTextures.cpp** | 擴充 GBuffer slot 相關內容 |
| **MaterialSceneTextureId.h** | 擴充 SceneTexture (PPI, Post Process Input) 相關 |
| **MaterialShared.h** | 擴充 SceneTexture (PPI, Post Process Input) 相關 |
| **SceneRenderTargetParameters.h** | 擴充 GBuffer slot, SceneTexture 相關 |
| **PostProcessBufferInspector.cpp** | 擴充 GBuffer slot, SceneTexture 相關 |
### Unreal shader headers and format (.ush & .usf)
| file | purpose |
|:------------------------------------------- |:-------------------------------------------------------------------------- |
| **Definitions.usf** | 擴充 Shading model 定義 |
| **ShadingCommon.ush** | 擴充 Material models 相關定義 |
| **MaterialTemplate.ush** | 擴充材質hlsl基礎模板 Material parameters 相關定義, 及 PPI 相關內容&定義 |
| **Common.ush** | 擴充 MRT (Multi Render Target) 大小 |
| **DecalCommon.ush** | 擴充 GBuffer slot 相關 |
| **SceneTexturesCommon.ush** | 擴充 GBuffer slot, SceneTexture 相關 |
| **BasePassCommon.ush** | 擴充一些基礎Pass定義 |
| **BasePassPixelShader.usf** | 修改 Gbuffer 相關參數內容,及擴充 GBuffer slot 相關 |
| **DeferredShadingCommon.ush** | 擴充 GBuffer slot 相關,以及 GBufferData, GBuffer slot 間的 Encode, Decode |
| **ShaderOutputCommon.ush** | 擴充 GBuffer slot 相關內容 |
| **PixelShaderOutputCommon.ush** | 擴充 GBuffer slot 相關內容 |
| **SSDCommon.ush** | 擴充 GBuffer slot, GBufferData 相關 |
| **ShadingModelsMaterial.ush** | 擴充參數解碼到 Shading Model 的內容(GbufferData) |
| **GBufferHelpers.ush** | 修改GBuffer Encode, Decode 用的輔助 functions |
| **ShadingModels.ush** | 每個MSM對應的BxDF都定義在這裡,可以調整或自定義 BxDF functions |
| **RayTracingDeferredShadingCommon.ush** | 擴充 GBuffer slot, GBufferData 相關 |
| **ShadingModelsSampling.ush** | 材質sampling相關function, 例如計算取樣PDF等 |
| **ClusteredDeferredShadingPixelShader.usf** | 擴充 Shading model 相關 |
| **ReflectionEnvironmentPixelShader.usf** | 調整反射相關Functions |
| **DeferredLightingCommon.ush** | 修改或擴充光照積分的function |
### 其他
| file | purpose |
| ----------------------------- | ------------------------- |
| **ConsoleVariables.ini** | 調整Shader Development 相關設定 |
# Expand Material Shading Model
## EngineTypes.h
Path: `Runtime/Engine/Classes/Engine/EngineTypes.h`
在這裡將自定義的 `Material Shading Model` 擴充到 EMaterialShadingModel。
* 擴充的項目必須在MSM_NUM前面
* 用MSM作前綴 (不確定前綴不是MSM是否導致無法編譯,UE編譯時在很多地方會強制某些Class要有對應前綴)
```cpp
...
MSM_Strata UMETA(DisplayName="Substrate", Hidden),
// [Toon][Add-Begin] @cc5568135
MSM_TOON UMETA(DisplayName = "Toon"),
// [Toon][Add-End] @cc5568135
MSM_NUM UMETA(Hidden),
...
```
## MaterialShader.cpp
Path: `Runtime/Engine/Private/Materials/MaterialShader.cpp`
擴充GetShadingModelString。
```cpp
...
case MSM_ThinTranslucent: ShadingModelName = TEXT("MSM_ThinTranslucent"); break;
// [Toon][Add-Begin] @cc5568135
case MSM_TOON: ShadingModelName = TEXT("MSM_TOON"); break;
// [Toon][Add-End] @cc5568135
default: ShadingModelName = TEXT("Unknown"); break;
...
```
擴充`UpdateMaterialShaderCompilingStats`
```cpp
// [Toon][Modify-Begin] @cc5568135 - Toon
//else if (ShadingModels.HasAnyShadingModel({ MSM_DefaultLit, MSM_Subsurface, MSM_PreintegratedSkin, MSM_ClearCoat, MSM_Cloth, MSM_SubsurfaceProfile, MSM_TwoSidedFoliage, MSM_SingleLayerWater, MSM_ThinTranslucent }))
else if (ShadingModels.HasAnyShadingModel({ MSM_DefaultLit, MSM_Subsurface, MSM_PreintegratedSkin, MSM_ClearCoat, MSM_Cloth, MSM_SubsurfaceProfile, MSM_TwoSidedFoliage, MSM_SingleLayerWater, MSM_ThinTranslucent, MSM_TOON }))
// [Toon][Modify-End] @cc5568135 2024/10/25
{
INC_DWORD_STAT_BY(STAT_ShaderCompiling_NumLitMaterialShaders, 1);
}
```
## HLSLMaterialTranslator.cpp
Path: `Runtime/Engine/Private/Materials/HLSLMaterialTranslator.cpp`
在 `GetMaterialEnvironment` 新增 Define。
```cpp
if (EnvironmentDefines->HasShadingModel(MSM_ThinTranslucent))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT"), TEXT("1"));
bMaterialRequestsDualSourceBlending = true;
}
// [Toon][Add-Begin] @cc5568135 - Add Toon define
if (EnvironmentDefines->HasShadingModel(MSM_TOON))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_TOON"), TEXT("1"));
}
// [Toon][Add-End] @cc5568135
if (EnvironmentDefines->bDisableForwardLocalLights)
{
OutEnvironment.SetDefine(TEXT("DISABLE_FORWARD_LOCAL_LIGHTS"), TEXT("1"));
}
```
## MaterialHLSLEmitter.cpp
Path: `Runtime/Engine/Private/Materials/MaterialHLSLEmitter.cpp`
在 `GetMaterialEnvironment` 新增 Define。
```cpp
if (ShadingModels.HasShadingModel(MSM_ThinTranslucent))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT"), TEXT("1"));
NumSetMaterials++;
bMaterialRequestsDualSourceBlending = true;
}
// [Toon][Add-Begin] @cc5568135 - Add Toon define
if (ShadingModels.HasShadingModel(MSM_TOON))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_TOON"), TEXT("1"));
NumSetMaterials++;
}
// [Toon][Add-End] @cc5568135 2024/10/24
if (ShadingModels.HasShadingModel(MSM_SingleLayerWater) && FDataDrivenShaderPlatformInfo::GetRequiresDisableForwardLocalLights(InPlatform))
{
OutEnvironment.SetDefine(TEXT("DISABLE_FORWARD_LOCAL_LIGHTS"), TEXT("1"));
}
```
## ShaderMaterial.h
Path: `Runtime/RenderCore/Public/ShaderMaterial.h`
在`FShaderMaterialPropertyDefines` 新增新的MSM。
```cpp
uint8 MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT : 1;
// [Toon][Add-Begin] @cc5568135 - Add Toon shading model
uint8 MATERIAL_SHADINGMODEL_TOON : 1;
// [Toon][Add-End] @cc5568135 2024/10/24
uint8 TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL : 1;
```
## PixelInspectorResult.h
Path: `Editor\PixelInspector\Private\PixelInspectorResult.h`
擴充define
```cpp
#define PIXEL_INSPECTOR_SHADINGMODELID_SUBSTRATE 12
// [Toon][Add-Begin] @cc5568135 - Toon
#define PIXEL_INSPECTOR_SHADINGMODELID_TOON 13
// [Toon][Add-End] @cc5568135 2024/10/25
#define PIXEL_INSPECTOR_SHADINGMODELID_MASK 0xF
```
## PixelInspectorResult.cpp
Path: `Editor/PixelInspector/Private/PixelInspectorResult.cpp`
擴充`PixelInspectorResult::DecodeShadingModel`
```cpp
case PIXEL_INSPECTOR_SHADINGMODELID_THIN_TRANSLUCENT:
return EMaterialShadingModel::MSM_ThinTranslucent;
// [Toon][Add-Begin] @cc5568135
case PIXEL_INSPECTOR_SHADINGMODELID_TOON:
return EMaterialShadingModel::MSM_TOON;
// [Toon][Add-End] @cc5568135 Last modified 2025/05/03
```
擴充`PixelInspectorResult::DecodeCustomData`
```cpp
case EMaterialShadingModel::MSM_Strata:
// [Toon][Modified begin] @cc5568135
case EMaterialShadingModel::MSM_TOON:
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
## ShaderGenerationUtil.cpp
Path: `Runtime\Engine\Private\ShaderCompiler\ShaderGenerationUtil.cpp`
擴充`ApplyFetchEnvironmentInternal`
```cpp
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT);
// [Toon][Add-Begin] @cc5568135
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_TOON);
// [Toon][Add-End] @cc5568135 2024/10/24
FETCH_COMPILE_BOOL(SINGLE_LAYER_WATER_SEPARATED_MAIN_LIGHT);
```
並在`DetermineUsedMaterialSlots` 設定新的MSM的 GBuffer Slots,設定CudstomData。
```cpp
// doesn't write to GBuffer
if (Mat.MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT)
{
}
// [Toon][Add-Begin] @cc5568135 - Add Toon
if (Mat.MATERIAL_SHADINGMODEL_TOON)
{
SetStandardGBufferSlots(Slots, bWriteEmissive, bHasTangent, bHasVelocity, bWritesVelocity, bHasStaticLighting, bIsSubstrateMaterial);
Slots[GBS_CustomData] = GetGBufferSlotUsage(bUseCustomData);
}
// [Toon][Add-End] @cc5568135 2024/10/24
```
# Expand Material Parameters
## SceneTypes.h
Path: `Runtime\Engine\Public\SceneTypes.h`
新增Material Parameter到EMaterialProperty。
```
MP_Displacement UMETA(Hidden),
// [Toon][Add-Begin] @cc5568135 - Toon
MP_ShadowColor UMETA(DisplayName = "Shadow Color"),
// [Toon][Add-End] @cc5568135 2024/10/24
```
## MaterialAttributeDefinitionMap.cpp
Path: `Runtime/Engine/Private/Materials/MaterialAttributeDefinitionMap.cpp`
在這裡設定MP的顯示名稱, 預設值, Guid。
**注意:`InitializeAttributeMap()` 這邊不能設定參數為`MCT_Float4`。**
```cpp
// 顯示名稱 FMaterialAttributeDefintion::CompileDefaultValue
...
if (Property == MP_ShadowColor && Compiler->GetCompiledShadingModels().HasShadingModel(MSM_TOON))
{
check(ValueType == MCT_Float3);
return Compiler->Constant3(0.0f, 0.0f, 0.0f);
}
// 預設值 FMaterialAttributeDefinitionMap::GetAttributeOverrideForMaterial
...
case MP_ShadowColor:
return LOCTEXT("ShadowColor", "Shadow Color");
...
//Guid FMaterialAttributeDefinitionMap::InitializeAttributeMap
...
Add(FGuid(0xf3ba8d73, 0x74144e85, 0xa49c806a, 0xfa83734a), TEXT("ShadowColor"), MP_ShadowColor, MCT_Float3, FVector4(0, 0, 0, 0), SF_Pixel);
...
```
擴充`GetAttributeOverrideForMaterial(...)`
```
// [Toon][Modified begin] @cc5568135
case MP_ShadowColor:
return LOCTEXT("ShadowColor", "Shadow Color");
...
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
## Material.h
path: `Runtime\Engine\Public\Materials\Material.h`
擴充 class `UMaterialEditorOnlyData`
```cpp
...
UPROPERTY()
FColorMaterialInput ShadowColor;
...
```
```cpp
// [Toon][Modified begin] @cc5568135
ENGINE_API bool HasShadowColorConnected() const;
...
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
## Material.cpp
path: `Runtime\Engine\Private\Materials\Material.cpp`
首先要調整`MP_MAX`大小
```cpp
// [Toon][Modify-Begin] @cc5568135 - Toon
//static_assert(MP_MAX == 35, "New material properties must have DoMaterialAttributeReorder called on them to ensure that any future reordering of property pins is correctly applied.");
static_assert(MP_MAX == 35 + 2, "New material properties must have DoMaterialAttributeReorder called on them to ensure that any future reordering of property pins is correctly applied.");
// [Toon][Modify-End] @cc5568135 2024/10/25
```
擴充`PostLoad`
```cpp
DoMaterialAttributeReorder(&EditorOnly->PixelDepthOffset, UEVer, RenderObjVer, UE5MainVer);
// [Toon][Add-Begin] @cc5568135 - Toon
DoMaterialAttributeReorder(&EditorOnly->ShadowColor, UEVer, RenderObjVer, UE5MainVer);
DoMaterialAttributeReorder(&EditorOnly->FaceForwardVector, UEVer, RenderObjVer, UE5MainVer);
// [Toon][Add-End] @cc5568135 2024/10/25
DoMaterialAttributeReorder(&EditorOnly->ShadingModelFromMaterialExpression, UEVer, RenderObjVer, UE5MainVer);
```
擴充`GetExpressionInputDescription`
```cpp
case MP_FrontMaterial: SetMaterialInputDescription(EditorOnly->FrontMaterial, false, OutDescription); return true;
// [Toon][Add-Begin] @cc5568135 - Toon
case MP_ShadowColor: SetMaterialInputDescription(EditorOnly->ShadowColor, false, OutDescription); return true;
case MP_FaceForwardVector: SetMaterialInputDescription(EditorOnly->FaceForwardVector, false, OutDescription); return true;
// [Toon][Add-End] @cc5568135 2024/10/25
```
擴充`CompilePropertyEx`
```cpp
// [Toon][Modified begin] @cc5568135
case MP_ShadowColor: return EditorOnly->ShadowColor.CompileWithDefault(Compiler, Property);
...
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
```cpp
// [Toon][Modify-Begin] @cc5568135 - No Reflection for Toon
//const bool bUnlitMaterial = ShadingModelID == SHADINGMODELID_UNLIT;
const bool bUnlitMaterial = ShadingModelID == SHADINGMODELID_UNLIT || ShadingModelID == SHADINGMODELID_TOON;
// [Toon][Modify-End] @cc5568135 2024/10/24
```
擴充`IsPropertyActive_Internal` 最下面`if (bSubstrateEnabled){...}else{/*add here*/}`
這裡設定Material parameters,在甚麼條件下才需要被顯示。
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
case MP_ShadowColor:
case MP_FaceForwardVector:
Active = ShadingModels.HasShadingModel(MSM_TOON);
break;
// [Toon][Add-End] @cc5568135 2024/10/25
```
擴充function
```cpp
// [Toon][Modified begin] @cc5568135
bool UMaterial::HasShadowColorConnected() const
{
return IsPropertyConnected(MP_ShadowColor);
}
...
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
## MaterialEditor.cpp
Path: `Editor/MaterialEditor/Private/MaterialEditor.cpp`
擴充`GetOnPromoteToParameterClass`
```cpp
case MP_Tangent:
// [Toon][Add-Begin] @cc5568135 - Toon
case MP_ShadowColor:
case MP_FaceForwardVector:
// [Toon][Add-End] @cc5568135 2024/10/25
return UMaterialExpressionVectorParameter::StaticClass();
```
## MaterialGraph.cpp
Path: `Editor/UnrealEd/Private/MaterialGraph.cpp`
擴充`RebuildGraphInternal`,可以加在最下面
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
MaterialInputs.Add(FMaterialInputInfo(FMaterialAttributeDefinitionMap::GetDisplayNameForMaterial(MP_ShadowColor, Material), MP_ShadowColor, LOCTEXT("ShadowColorToolTip", "Shadow Color")));
MaterialInputs.Add(FMaterialInputInfo(FMaterialAttributeDefinitionMap::GetDisplayNameForMaterial(MP_FaceForwardVector, Material), MP_FaceForwardVector, LOCTEXT("FaceForwardVectorToolTip", "Face Forward Vector")));
// [Toon][Add-End] @cc5568135 2024/10/25
```
## MaterialExpressionMakeMaterialAttributes.h
Path: `Runtime/Engine/Classes/Materials/MaterialExpressionMakeMaterialAttributes.h`
擴充`UMaterialExpressionMakeMaterialAttributes `
```cpp
UPROPERTY()
FExpressionInput Displacement;
// [Toon][Add-Begin] @cc5568135 - Toon
UPROPERTY()
FExpressionInput ShadowColor;
UPROPERTY()
FExpressionInput FaceForwardVector;
// [Toon][Add-End] @cc5568135 2024/10/25
```
## MaterialExpressions.cpp
Path: `Runtime/Engine/Private/Materials/MaterialExpressions.cpp`
調整`MP_MAX`大小,有**兩個地方**要改
```cpp
// [Toon][Modify-Begin] @cc5568135 - Toon
//static_assert(MP_MAX == 35,
// "New material properties should be added to the end of the outputs for this expression. \
// The order of properties here should match the material results pins, the make material attributes node inputs and the mapping of IO indices to properties in GetMaterialPropertyFromInputOutputIndex().\
// Insertions into the middle of the properties or a change in the order of properties will also require that existing data is fixed up in DoMaterialAttributesReorder().\
// ");
static_assert(MP_MAX == 35 + 2,
"New material properties should be added to the end of the outputs for this expression. \
The order of properties here should match the material results pins, the make material attributes node inputs and the mapping of IO indices to properties in GetMaterialPropertyFromInputOutputIndex().\
Insertions into the middle of the properties or a change in the order of properties will also require that existing data is fixed up in DoMaterialAttributesReorder().\
");
// [Toon][Modify-End] @cc5568135 2024/10/25
```
擴充`GetExpressionInput`
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
case MP_ShadowColor: return &ShadowColor;
case MP_FaceForwardVector: return &FaceForwardVector;
// [Toon][Add-End] @cc5568135 2024/10/25
```
擴充`UMaterialExpressionMakeMaterialAttributes::Compile`
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
case MP_ShadowColor: Ret = ShadowColor.Compile(Compiler); Expression = ShadowColor.Expression; break;
case MP_FaceForwardVector: Ret = FaceForwardVector.Compile(Compiler); Expression = FaceForwardVector.Expression; break;
// [Toon][Add-End] @cc5568135 2024/10/25
```
**注意`Serialize` `UMaterialExpressionBreakMaterialAttributes` `BuildPropertyToIOIndexMap`參數順序/Index要一致**
擴充`BuildPropertyToIOIndexMap`
```cpp
// [Toon][Modify-Begin] @cc5568135 - Toon
//PropertyToIOIndexMap.Add(MP_ShadingModel, 25);
//PropertyToIOIndexMap.Add(MP_Displacement, 26);
PropertyToIOIndexMap.Add(MP_ShadowColor, 25);
PropertyToIOIndexMap.Add(MP_FaceForwardVector, 26);
PropertyToIOIndexMap.Add(MP_ShadingModel, 27);
PropertyToIOIndexMap.Add(MP_Displacement, 28);
// [Toon][Modify-End] @cc5568135 2024/10/25
```
擴充`UMaterialExpressionBreakMaterialAttributes::Serialize`
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
Outputs[OutputIndex].SetMask(1, 1, 1, 1, 0); ++OutputIndex; // ShadowColor
Outputs[OutputIndex].SetMask(1, 1, 1, 1, 0); ++OutputIndex; // FaceForwardVector
// [Toon][Add-End] @cc5568135 2024/10/25
```
擴充`UMaterialExpressionBreakMaterialAttributes::UMaterialExpressionBreakMaterialAttributes`
```cpp
Outputs.Add(FExpressionOutput(TEXT("PixelDepthOffset"), 1, 1, 0, 0, 0));
// [Toon][Add-Begin] @cc5568135 - Toon
Outputs.Add(FExpressionOutput(TEXT("ShadowColor"), 1, 1, 1, 1, 0));
Outputs.Add(FExpressionOutput(TEXT("FaceForwardVector"), 1, 1, 1, 1, 0));
// [Toon][Add-End] @cc5568135 2024/10/25
```
擴充`GetConnectedInputs()`
```cpp
// [Toon][Modified begin] @cc5568135
if (ShadowColor.Expression != nullptr) Out |= (1ull << uint64(MP_ShadowColor));
...
```
## HLSLMaterialTranslator.cpp
在上一章有增加MSM的部分,這邊是PM的部分。
擴充 Construction (`FHLSLMaterialTranslator::FHLSLMaterialTranslator`)
```cpp
SharedPixelProperties[MP_Displacement] = true;
// [Toon][Add-Begin] @cc5568135 - Toon
SharedPixelProperties[MP_ShadowColor] = true;
SharedPixelProperties[MP_FaceForwardVector] = true;
// [Toon][Add-End] @cc5568135 2024/10/25
```
擴充`TranslateMaterial()`
```cpp
Chunk[MP_Displacement] = Material->CompilePropertyAndSetMaterialProperty(MP_Displacement, this);
// [Toon][Add-Begin] @cc5568135 - Toon
Chunk[MP_ShadowColor] = Material->CompilePropertyAndSetMaterialProperty(MP_ShadowColor, this);
Chunk[MP_FaceForwardVector] = Material->CompilePropertyAndSetMaterialProperty(MP_FaceForwardVector, this);
// [Toon][Add-End] @cc5568135 2024/10/25
```
## MaterialHLSLEmitter.cpp
擴充 `bool MaterialEmitHLSL(...)`
```
SharedPixelProperties[MP_Displacement] = true;
// [Toon][Add-Begin] @cc5568135 - Toon
SharedPixelProperties[MP_ShadowColor] = true;
...
// [Toon][Add-End] @cc5568135 Last modified 2025/05/02
```
## MaterialCachedData.cpp
Path: `Runtime/Engine/Public/MaterialCachedData.h`
擴充`UpdateForExpressions`
```cpp
SetMatAttributeConditionally(EMaterialProperty::MP_Displacement, MakeMatAttributes->Displacement.IsConnected());
// [Toon][Add-Begin] @cc5568135 - Toon
SetMatAttributeConditionally(EMaterialProperty::MP_ShadowColor, MakeMatAttributes->ShadowColor.IsConnected());
SetMatAttributeConditionally(EMaterialProperty::MP_FaceForwardVector, MakeMatAttributes->FaceForwardVector.IsConnected());
// [Toon][Add-End] @cc5568135 2024/10/25
```
## ShaderMaterialDerivedHelpers.cpp
Path: `Runtime/RenderCore/Private/ShaderMaterialDerivedHelpers.cpp`
如果要在GBuffer寫入CustomData,在`ShaderMaterialDerivedHelpers.cpp`修改`Dst.WRITES_CUSTOMDATA_TO_GBUFFER = ...`
```cpp
// Only some shader models actually need custom data.
// [Toon][Modified begin] @cc5568135
// Dst.WRITES_CUSTOMDATA_TO_GBUFFER = (Dst.USES_GBUFFER && (Mat.MATERIAL_SHADINGMODEL_SUBSURFACE || Mat.MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || Mat.MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || Mat.MATERIAL_SHADINGMODEL_CLEAR_COAT || Mat.MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || Mat.MATERIAL_SHADINGMODEL_HAIR || Mat.MATERIAL_SHADINGMODEL_CLOTH || Mat.MATERIAL_SHADINGMODEL_EYE));
Dst.WRITES_CUSTOMDATA_TO_GBUFFER = (Dst.USES_GBUFFER && (Mat.MATERIAL_SHADINGMODEL_SUBSURFACE || Mat.MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || Mat.MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || Mat.MATERIAL_SHADINGMODEL_CLEAR_COAT || Mat.MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || Mat.MATERIAL_SHADINGMODEL_HAIR || Mat.MATERIAL_SHADINGMODEL_CLOTH || Mat.MATERIAL_SHADINGMODEL_EYE || Mat.MATERIAL_SHADINGMODEL_TOON));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
# Expand Gbuffer
## Gbuffer slots 說明
Material Parameters 並非一個參數對應一個獨立的 Gbuffer slots,而是在不同設定下寫進不同的 Gbuffer slots。
原始 Source code 有 `GBufferA` 至 `GBufferF`, `GBufferVelocity` 7 個 half4 參數的GBuffer。
Gbuffer Slots 對應如下:
| Slot / Channel | r | g | b | a |
|:--------------- | -------------------------- | -------------------------- |:-------------------------- |:-------------------------- |
| GBufferA | WorldNormal.r | WorldNormal.g | WorldNormal.b | PerObjectGBufferData |
| GBufferB | Metallic | Specular | Roughness | ShadingModelID |
| GBufferC | BaseColor.r | BaseColor.g | BaseColor.b | AO |
| GBufferD | CustomData.r | CustomData.g | CustomData.b | CustomData.a |
| GBufferE | PrecomputedShadowFactors.r | PrecomputedShadowFactors.g | PrecomputedShadowFactors.b | PrecomputedShadowFactors.a |
| GBufferF | WorldTangent.x | WorldTangent.y | WorldTangent.z | Anisotropy |
| GBufferVelocity | Velocity.r | Velocity.g | Velocity.b | Velocity.a |
CustomData 通常被用來存不同 Shading model 所需要的參數,設定位置在`ShadingModelsMaterial.ush` 的`void SetGBufferForShadingModel`。
例如 Shading model = Subsurface時:
```cpp
GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor);
GBuffer.CustomData.a = Opacity;
```
可以自行判斷是不是需要增加 Slot。
## Gbuffer Encode, Decode 自動生成說明
似乎在UE5版本之後(應該5.0開始就已經改了,5.3確定是如此),官方把原本在`DeferredShadingCommon.ush`定義的`EncodeGBuffer(...)` `DecodeGBufferData(...)` 內容都以捨棄,改用`GBufferInfo.cpp`等檔案來做設定並自動生成 hlsl。
可以在`BasePassPixelShader`看到以下Code,改用自動生成的`EncodeGBufferToMRT(...)`來達到Encode目的。
```cpp
// this is the new encode, the older encode is the #else, keeping it around briefly until the new version is confirmed stable.
#if 1
```
### 踩雷心得
想要在Gbuffer裡面塞進新的參數,必須先在`enum EGBufferSlot`定義新的GBS內容,然後在`GBufferInfo.cpp`新增對應TargetGBuffer欄位的對應。
我新增了兩個GBuffer: GBufferG, GBufferH,不過途中遇到不少問題。
造成Compile錯誤的踩雷整理,***並不是非常確定***這些就是造成錯誤的確切原因,可以當作參考。
注意點:
* TargetGBufferG 每個欄位應該都需要有被設定,不能有部分被設定、部分沒有的情況。
```cpp
// 四個欄位都有設定,這樣應該比較沒問題
Info.Slots[GBS_ShadowColor] = FGBufferItem(GBS_ShadowColor, GBC_Raw_Unorm_8_8_8_8, GBCH_Both);
Info.Slots[GBS_ShadowColor].Packing[0] = FGBufferPacking(TargetGBufferG, 0, 0);
Info.Slots[GBS_ShadowColor].Packing[1] = FGBufferPacking(TargetGBufferG, 1, 1);
Info.Slots[GBS_ShadowColor].Packing[2] = FGBufferPacking(TargetGBufferG, 2, 2);
Info.Slots[GBS_ShadowColor].Packing[3] = FGBufferPacking(TargetGBufferG, 3, 3);
```
* 不能有重複設定到欄位的部分,像是我想要對CstomData再做設定會造成錯誤。
```cpp
// 應該會造成錯誤, TargetGBufferD 是給 CustomData用。已經被設定過了
Info.Slots[GBS_FaceVectors] = FGBufferItem(GBS_FaceForwwardVector, GBC_Raw_Unorm_8_8, GBCH_Both);
Info.Slots[GBS_FaceVectors].Packing[0] = FGBufferPacking(TargetGBufferD, 0, 0);
Info.Slots[GBS_FaceVectors].Packing[1] = FGBufferPacking(TargetGBufferD, 1, 1);
```
* 如果新增的GBS要設定到新的GBuffer slot,建議兩者都是 float4 (四維數)。用兩個float2 的 GBS 去塞一個 GBuffer slot 會出錯。
```cpp!
//寫這樣出錯
Info.Slots[GBS_FaceForwardVector] = FGBufferItem(GBS_FaceForwardVector, GBC_Raw_Unorm_8_8, GBCH_Both);
Info.Slots[GBS_FaceForwardVector].Packing[0] = FGBufferPacking(TargetGBufferH, 0, 0);
Info.Slots[GBS_FaceForwardVector].Packing[1] = FGBufferPacking(TargetGBufferH, 1, 1);
Info.Slots[GBS_FaceRightwardVector] = FGBufferItem(GBS_FaceRightwardVector, GBC_Raw_Unorm_8_8, GBCH_Both);
Info.Slots[GBS_FaceRightwardVector].Packing[0] = FGBufferPacking(TargetGBufferH, 2, 2);
Info.Slots[GBS_FaceRightwardVector].Packing[1] = FGBufferPacking(TargetGBufferH, 3, 3);
//改成這樣就沒問題
Info.Slots[GBS_FaceVectors] = FGBufferItem(GBS_FaceVectors, GBC_Raw_Unorm_8_8_8_8, GBCH_Both);
Info.Slots[GBS_FaceVectors].Packing[0] = FGBufferPacking(TargetGBufferH, 0, 0);
Info.Slots[GBS_FaceVectors].Packing[1] = FGBufferPacking(TargetGBufferH, 1, 1);
Info.Slots[GBS_FaceVectors].Packing[2] = FGBufferPacking(TargetGBufferH, 2, 2);
Info.Slots[GBS_FaceVectors].Packing[3] = FGBufferPacking(TargetGBufferH, 3, 3);
```
* `ShaderGenerationUtil.cpp`當中的`FString GetSlotTextName(EGBufferSlot Slot)` return的字串對應到 `struct FGBufferData` 裡面的名稱。當然,value type 的維度也需要對上。
* 呈上兩項,如果 MP (Materail parameter) 的參數設定不是 float4 (確實也沒辦法是float4),可以在 `struct FGBufferData` 新增一個對應 GBS 的 half4 ,並在 `BasePassPixelShader.usf` Out.MRT 被設定之前,Gbuffer參數互換過去就可以了。
```cpp
// 舉例來說,定義了 MP_FaceForwardVector MP_FaceRightwardVector (不需要z值)
// BasePassPixelShader.usf FPixelShaderInOut_MainPS, Out.MRT 被設定之前
GBuffer.FaceVectors.rg = GBuffer.FaceForwardVector.rg;
GBuffer.FaceVectors.ba = GBuffer.FaceRightwardVector.rg;
// DeferredShadingCommon.ush struct FGBufferData
half3 FaceForwardVector;
half3 FaceRightwardVector;
half4 FaceVectors;
```
## GBufferInfo.h
Path`Runtime\RenderCore\Public\GBufferInfo.h`
擴充`EGBufferSlot`,在GBS_Num上面。
```cpp
// [Toon][Modified begin] @cc5568135
GBS_ShadowColor, // RGB8
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充`FGBufferBindings`
```cpp
FGBufferBinding GBufferE;
// [Toon][Modified begin] @cc5568135
FGBufferBinding GBufferG;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
FGBufferBinding GBufferVelocity;
```
調整`FGBufferInfo` MaxTargets
```cpp
// [Toon][Modified begin] @cc5568135
// static const int MaxTargets = 8;
static const int MaxTargets = 8 + 1 ;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## GBufferInfo.cpp
擴充`FetchLegacyGBufferInfo`
這裡是對應Render Target (RT)的 index,預設未啟用是-1
```cpp
int32 TargetGBufferF = -1;
// [Toon][Modified begin] @cc5568135
int32 TargetGBufferG = -1;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
int32 TargetVelocity = -1;
```
增加 Info.NumTargets
```cpp
else
{
Info.NumTargets = Params.bHasPrecShadowFactor ? 7 : 6;
}
// [Toon][Modified begin] @cc5568135
Info.NumTargets++;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
// good to see the quality loss due to precision in the gbuffer
const bool bHighPrecisionGBuffers = (Params.LegacyFormatIndex >= EGBufferFormat_Force16BitsPerChannel);
```
擴充`if (Params.bHasVelocity == 0 && Params.bHasTangent == 0)`底下內容
```cpp
// This code should match TBasePassPS
if (Params.bHasVelocity == 0 && Params.bHasTangent == 0)
{
TargetGBufferD = 4;
Info.Targets[4].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferD"), false, true, true, true);
TargetSeparatedMainDirLight = 5;
if (Params.bHasPrecShadowFactor)
{
TargetGBufferE = 5;
Info.Targets[5].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferE"), false, true, true, true);
TargetSeparatedMainDirLight = 6;
}
// [Toon][Modified begin] @cc5568135
TargetGBufferG = TargetGBufferE == -1 ? 5 : TargetGBufferE + 1;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
}
else if (Params.bHasVelocity)
{
TargetVelocity = 4;
TargetGBufferD = 5;
// note the false for use extra flags for velocity, not quite sure of all the ramifications, but this keeps it consistent with previous usage
Info.Targets[4].Init(Params.bUsesVelocityDepth ? GBT_Unorm_16_16_16_16 : (IsAndroidOpenGLESPlatform(Params.ShaderPlatform) ? GBT_Float_16_16 : GBT_Unorm_16_16), TEXT("Velocity"), false, true, true, false);
Info.Targets[5].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferD"), false, true, true, true);
TargetSeparatedMainDirLight = 6;
if (Params.bHasPrecShadowFactor)
{
TargetGBufferE = 6;
Info.Targets[6].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferE"), false, true, true, false);
TargetSeparatedMainDirLight = 7;
}
// [Toon][Modified begin] @cc5568135
TargetGBufferG = TargetGBufferE == -1 ? 6 : TargetGBufferE + 1;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
}
else if (Params.bHasTangent)
{
TargetGBufferF = 4;
TargetGBufferD = 5;
Info.Targets[4].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferF"), false, true, true, true);
Info.Targets[5].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferD"), false, true, true, true);
TargetSeparatedMainDirLight = 6;
if (Params.bHasPrecShadowFactor)
{
TargetGBufferE = 6;
Info.Targets[6].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferE"), false, true, true, true);
TargetSeparatedMainDirLight = 7;
}
// [Toon][Modified begin] @cc5568135
TargetGBufferG = TargetGBufferE == -1 ? 6 : TargetGBufferE + 1;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
}
else
{
// should never hit this path
check(0);
}
// [Toon][Modified begin] @cc5568135
Info.Targets[TargetGBufferG].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferG"), false, true, true, true);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
```cpp
Info.Slots[GBS_CustomData].Packing[2] = FGBufferPacking(TargetGBufferD, 2, 2);
Info.Slots[GBS_CustomData].Packing[3] = FGBufferPacking(TargetGBufferD, 3, 3);
// [Toon][Modified begin] @cc5568135
Info.Slots[GBS_ShadowColor] = FGBufferItem(GBS_ShadowColor, GBC_Raw_Unorm_8_8_8, GBCH_Both);
Info.Slots[GBS_ShadowColor].Packing[0] = FGBufferPacking(TargetGBufferG, 0, 0);
Info.Slots[GBS_ShadowColor].Packing[1] = FGBufferPacking(TargetGBufferG, 1, 1);
Info.Slots[GBS_ShadowColor].Packing[2] = FGBufferPacking(TargetGBufferG, 2, 2);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## SceneRendering.h
Path `Runtime\Renderer\Private\SceneRendering.h`
```cpp
ETextureCreateFlags GBufferF;
// [Toon][Modified begin] @cc5568135
ETextureCreateFlags GBufferG;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
ETextureCreateFlags GBufferVelocity;
```
## SceneRendering.cpp
Path `Runtime\Renderer\Private\SceneRendering.cpp`
```cpp
// [Toon][Modified begin] @cc5568135
FASTVRAM_CVAR(GBufferG, 0);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
FASTVRAM_CVAR(GBufferVelocity, 0);
```
擴充`Update()`
```cpp
bDirty |= UpdateTextureFlagFromCVar(CVarFastVRam_GBufferF, GBufferF);
// [Toon][Modified begin] @cc5568135
bDirty |= UpdateTextureFlagFromCVar(CVarFastVRam_GBufferG, GBufferG);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
bDirty |= UpdateTextureFlagFromCVar(CVarFastVRam_GBufferVelocity, GBufferVelocity);
```
## SceneTextureParameters.h
Path `Runtime\Renderer\Private\SceneTextureParameters.h`
擴充`FSceneTextures`
```cpp
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferFTexture)
// [Toon][Modified begin] @cc5568135
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferGTexture)
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferVelocityTexture)
```
## SceneTextureParameters.cpp
擴充`GetSceneTextureParameters`
Path`Runtime\Renderer\Private\SceneTextureParameters.cpp`
```cpp
Parameters.GBufferFTexture = GetIfProduced(SceneTextures.GBufferF, SystemTextures.MidGrey);
// [Toon][Modified begin] @cc5568135
Parameters.GBufferGTexture = GetIfProduced(SceneTextures.GBufferG);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充另一個`GetSceneTextureParameters`
```cpp
Parameters.GBufferFTexture = (*SceneTextureUniformBuffer)->GBufferFTexture;
// [Toon][Modified begin] @cc5568135
Parameters.GBufferGTexture = (*SceneTextureUniformBuffer)->GBufferGTexture;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
Parameters.GBufferVelocityTexture = (*SceneTextureUniformBuffer)->GBufferVelocityTexture;
```
## SceneTexturesConfig.h
Path`Runtime\Engine\Private\SceneTexturesConfig.h`
擴充`FSceneTextureUniformParameters`
```cpp
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferFTexture)
// [Toon][Modified begin] @cc5568135
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferGTexture)
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## SceneTexturesConfig.cpp
Path`Runtime\Engine\Private\SceneTexturesConfig.cpp`
擴充`SetupMobileGBufferFlags`
```cpp
Bindings.GBufferE.Flags |= AddFlags;
// [Toon][Modified begin] @cc5568135
Bindings.GBufferG.Flags |= AddFlags;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
...
Bindings.GBufferE.Flags &= (~RemoveFlags);
// [Toon][Modified begin] @cc5568135
Bindings.GBufferG.Flags &= (~RemoveFlags);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
...
OverrideB8G8R8A8(Bindings.GBufferE);
// [Toon][Modified begin] @cc5568135
OverrideB8G8R8A8(Bindings.GBufferG);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充`Init`
```cpp
BindingCache.Bindings[Layout].GBufferE = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferE"), ShaderPlatform);
// [Toon][Modified begin] @cc5568135
BindingCache.Bindings[Layout].GBufferG = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferG"), ShaderPlatform);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
BindingCache.Bindings[Layout].GBufferVelocity = FindGBufferBindingByName(GBufferInfo, TEXT("Velocity"), ShaderPlatform);
```
擴充`GetGBufferRenderTargetsInfo`
```cpp
IncludeBindingIfValid(Bindings.GBufferE);
// [Toon][Modified begin] @cc5568135
IncludeBindingIfValid(Bindings.GBufferG);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
IncludeBindingIfValid(Bindings.GBufferVelocity);
```
## SceneTextures.h
Path `Runtime\Renderer\Private\SceneTextures.h`
```cpp
FRDGTextureRef GBufferF{};
// [Toon][Modified begin] @cc5568135
FRDGTextureRef GBufferG{};
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## SceneTextures.cpp
Path`Runtime\Renderer\Private\SceneTextures.cpp`
擴充`InitializeViewFamily`
```cpp
...
SceneTextures.GBufferF = GraphBuilder.CreateTexture(Desc, TEXT("GBufferF"));
}
// [Toon][Modified begin] @cc5568135
if (Bindings.GBufferG.Index >= 0)
{
const FRDGTextureDesc Desc(Config.bRequireMultiView ?
FRDGTextureDesc::Create2DArray(Config.Extent, Bindings.GBufferG.Format, FClearValueBinding::Transparent, Bindings.GBufferG.Flags | FlagsToAdd | GFastVRamConfig.GBufferG, 2) :
FRDGTextureDesc::Create2D(Config.Extent, Bindings.GBufferG.Format, FClearValueBinding::Transparent, Bindings.GBufferG.Flags | FlagsToAdd | GFastVRamConfig.GBufferG));
SceneTextures.GBufferG = GraphBuilder.CreateTexture(Desc, TEXT("GBufferG"));
}
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充`FGBufferEntry GBufferEntries[]`
```cpp
{ TEXT("GBufferE"), GBufferE, Bindings.GBufferE.Index },
// [Toon][Modified begin] @cc5568135
{ TEXT("GBufferG"), GBufferG, Bindings.GBufferG.Index },
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充 `GetSceneTexture`
```cpp
case ESceneTexture::GBufferF: return SceneTextures.GBufferF;
// [Toon][Modified begin] @cc5568135
case ESceneTexture::GBufferG: return SceneTextures.GBufferG;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充`SetupSceneTextureUniformParameters`
```cpp
SceneTextureParameters.GBufferFTexture = SystemTextures.MidGrey;
// [Toon][Modified begin] @cc5568135
SceneTextureParameters.GBufferGTexture = SystemTextures.Black;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
```cpp
if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferF) && HasBeenProduced(SceneTextures->GBufferF))
{
SceneTextureParameters.GBufferFTexture = SceneTextures->GBufferF;
}
// [Toon][Modified begin] @cc5568135
if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferG) && HasBeenProduced(SceneTextures->GBufferG))
{
SceneTextureParameters.GBufferGTexture = SceneTextures->GBufferG;
}
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## MaterialSceneTextureId.h
Path `Runtime\Engine\Public\MaterialSceneTextureId.h`
擴充`ESceneTextureId`,可以讓SceneTexture擷取到新的Gbuffer。要注意這個Enum的上限為31。
```
/** Material anisotropy, single channel (GBuffer) */
PPI_Anisotropy UMETA(DisplayName = "Anisotropy"),
// [Toon][Modified begin] @cc5568135
PPI_CustomExtraDataA UMETA(DisplayName = "ToonShadowColor"),
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## MaterialShared.h
Path `Runtime\Engine\Public\MaterialShared.h`
擴充`NeedsGBuffer`
```cpp
IsSceneTextureUsed(PPI_StoredSpecular) ||
// [Toon][Modified begin] @cc5568135
IsSceneTextureUsed(PPI_CustomExtraDataA) ||
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
IsSceneTextureUsed(PPI_Velocity);
```
## SceneRenderTargetParameters.h
Path `Runtime\Renderer\Public\SceneRenderTargetParameters.h`
擴充`ESceneTexture`
```cpp
GBufferF,
// [Toon][Modified begin] @cc5568135
GBufferG,
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
修改`ESceneTextureSetupMode`
```cpp
GBufferF = 1 << 8,
// [Toon][Modified begin] @cc5568135
// SSAO = 1 << 9,
//CustomDepth = 1 << 10,
//GBuffers = GBufferA | GBufferB | GBufferC | GBufferD | GBufferE | GBufferF,
GBufferG = 1 << 9,
SSAO = 1 << 10,
CustomDepth = 1 << 11,
GBuffers = GBufferA | GBufferB | GBufferC | GBufferD | GBufferE | GBufferF | GBufferG,
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## PostProcessBufferInspector.cpp
Path `Runtime\Renderer\Private\PostProcess\PostProcessBufferInspector.cpp`
擴充`FPixelInspectorParameters`
```cpp
RDG_TEXTURE_ACCESS(GBufferF, ERHIAccess::CopySrc)
// [Toon][Modified begin] @cc5568135
RDG_TEXTURE_ACCESS(GBufferG, ERHIAccess::CopySrc)
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充`ProcessPixelInspectorRequests` (// GBuffer BCDEF)
```cpp
if (Parameters.GBufferF)
{
FRHITexture* SourceBufferF = Parameters.GBufferF->GetRHI();
if (DestinationBufferBCDEF->GetFormat() == SourceBufferF->GetFormat())
{
FRHICopyTextureInfo CopyInfo;
CopyInfo.SourcePosition = SourcePoint;
CopyInfo.Size = FIntVector(1, 1, 1);
RHICmdList.CopyTexture(SourceBufferF, DestinationBufferBCDEF, CopyInfo);
}
}
// [Toon][Modified begin] @cc5568135
if (Parameters.GBufferG)
{
FRHITexture* SourceBufferG = Parameters.GBufferG->GetRHI();
if (DestinationBufferBCDEF->GetFormat() == SourceBufferG->GetFormat())
{
FRHICopyTextureInfo CopyInfo;
CopyInfo.SourcePosition = SourcePoint;
CopyInfo.DestPosition = FIntVector(4, 0, 0);
CopyInfo.Size = FIntVector(1, 1, 1);
RHICmdList.CopyTexture(SourceBufferG, DestinationBufferBCDEF, CopyInfo);
}
}
```
擴充`AddPixelInspectorPass`
```cpp
PassParameters->GBufferF = SceneTextures.GBufferFTexture;
// [Toon][Modified begin] @cc5568135
PassParameters->GBufferG = SceneTextures.GBufferGTexture;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## ShaderGenerationUtil.cpp
Path `Runtime\Engine\Private\ShaderCompiler\ShaderGenerationUtil.cpp`
擴充`GetSlotTextName`,*這裡return TEXT 字串要與FGBufferData名稱一致* (待確認)。
```cpp
case GBS_SeparatedMainDirLight:
return TEXT("SeparatedMainDirLight");
// [Toon][Modified begin] @cc5568135
case GBS_ShadowColor:
return TEXT("ShadowColor");
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
擴充前一章修改過的`DetermineUsedMaterialSlots`
```cpp
// [Toon][Modified begin] @cc5568135
if (Mat.MATERIAL_SHADINGMODEL_TOON)
{
SetStandardGBufferSlots(Slots, bWriteEmissive, bHasTangent, bHasVelocity, bWritesVelocity, bHasStaticLighting, bIsSubstrateMaterial);
Slots[GBS_CustomData] = GetGBufferSlotUsage(bUseCustomData);
Slots[GBS_ShadowColor] = GetGBufferSlotUsage(bUseCustomData);
}
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
# Expand Unreal Shaders
只修改 `.ush` `.usf` 檔案時,直接重開專案 Compile Shaders 即可,不用重新VS Build,也不用重新開一次 `UnrealEditor.exe`
## Definitions.usf
Path: `Shaders/Private/Definitions.usf`
新增 `#define`
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
#ifndef MATERIAL_SHADINGMODEL_TOON
#define MATERIAL_SHADINGMODEL_TOON 0
#endif
// [Toon][Add-End] @cc5568135 2024/10/24
```
## ShadingCommon.ush
Path: `Shaders/Private/ShadingCommon.ush`
擴充`SHADINGMODELID`,需要改原本`SHADINGMODELID_NUM`的數值。
```cpp
// #define SHADINGMODELID_NUM 13
// [Toon][Modify-Begin] @cc5568135 - Toon
#define SHADINGMODELID_TOON 13
#define SHADINGMODELID_NUM 14
// [Toon][Modify-End] @cc5568135 2024/10/24
```
擴充`GetShadingModelColor`
```cpp
else if (ShadingModelID == SHADINGMODELID_THIN_TRANSLUCENT) return float3(1.0f, 0.8f, 0.3f);
// [Toon][Add-Begin] @cc5568135 - Toon
else if (ShadingModelID == SHADINGMODELID_TOON) return float3(0.2f, 0.8f, 0.8f);
// [Toon][Add-End] @cc5568135 2024/10/24
```
```cpp
case SHADINGMODELID_THIN_TRANSLUCENT: return float3(1.0f, 0.8f, 0.3f);
// [Toon][Add-Begin] @cc5568135 - Toon
case SHADINGMODELID_TOON: return float3(0.2f, 0.8f, 0.8f);
// [Toon][Add-End] @cc5568135 2024/10/24
```
## MaterialTemplate.ush
Path: `Shaders/Private/MaterialTemplate.ush`
擴充
```cpp
// [Toon][Add-Begin] @cc5568135 - Toon
half3 GetMaterialShadowColorRaw(FPixelMaterialInputs PixelMaterialInputs)
{
return PixelMaterialInputs.ShadowColor;
}
half3 GetMaterialShadowColor(FPixelMaterialInputs PixelMaterialInputs)
{
return saturate(GetMaterialShadowColorRaw(PixelMaterialInputs));
}
half3 GetMaterialFaceForwardVectorRaw(FPixelMaterialInputs PixelMaterialInputs)
{
return PixelMaterialInputs.FaceForwardVector;
}
half3 GetMaterialFaceForwardVector(FPixelMaterialInputs PixelMaterialInputs)
{
return saturate(GetMaterialFaceForwardVectorRaw(PixelMaterialInputs));
}
// [Toon][Add-End] @cc5568135 2024/10/26
half GetMaterialAmbientOcclusionRaw(FPixelMaterialInputs PixelMaterialInputs)
{
return PixelMaterialInputs.AmbientOcclusion;
}
```
如有需要,新增PPI
```cpp
#define PPI_Anisotropy 30
// [Toon][Modified begin] @cc5568135
#define PPI_ShadowColor 31
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
```cpp
case PPI_Anisotropy: return ScreenSpaceData.GBuffer.Anisotropy;
// [Toon][Modified begin] @cc5568135
case PPI_ShadowColor: return float4(ScreenSpaceData.GBuffer.ShadowColor, 0);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
```
## Common.ush
Path `Shaders\Private\Common.ush`
擴充`FPixelShaderOut`,如有增加 Gbuffer Slots 才要調整。
```cpp
struct FPixelShaderOut
{
// [0..7], only usable if PIXELSHADEROUTPUT_MRT0, PIXELSHADEROUTPUT_MRT1, ... is 1
// [Toon][Modified begin] @cc5568135
// float4 MRT[8];
float4 MRT[8 + 1];
// [Toon][Modified end] @cc5568135 Last modified 2025/05/07
```
## DecalCommon.ush
Path `Shaders\Private\DecalCommon.ush`
如有新增GBuffer Slot,擴充`DecalCommonOutput`
```cpp
float4 OutTarget5 = 0;
float4 OutTarget6 = 0;
// [Toon][Modified begin] @cc5568135
float4 OutTarget7 = 0;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
## SceneTexturesCommon.ush
Path `Shaders\Private\SceneTexturesCommon.ush`
如有新增GBuffer,擴充 #define `SceneTexturesStruct`
```cpp
#define SceneTexturesStruct_GBufferFTextureSampler SceneTexturesStruct.PointClampSampler
// [Toon][Modified begin] @cc5568135
#define SceneTexturesStruct_GBufferGTextureSampler SceneTexturesStruct.PointClampSampler
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
#define SceneTexturesStruct_GBufferVelocityTextureSampler SceneTexturesStruct.PointClampSampler
```
## BasePassCommon.ush
Path: `Shaders/Private/BasePassCommon.ush`
這裡可以透過修改`#define WRITES_CUSTOMDATA_TO_GBUFFER`
設定新的MSM要不要把CustomData加進GBuffer。
```cpp
// Only some shader models actually need custom data.
// [Toon][Modified begin] @cc5568135
//#define WRITES_CUSTOMDATA_TO_GBUFFER (USES_GBUFFER && (MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || MATERIAL_SHADINGMODEL_CLEAR_COAT || MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || MATERIAL_SHADINGMODEL_HAIR || MATERIAL_SHADINGMODEL_CLOTH || MATERIAL_SHADINGMODEL_EYE))
#define WRITES_CUSTOMDATA_TO_GBUFFER (USES_GBUFFER && (MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || MATERIAL_SHADINGMODEL_CLEAR_COAT || MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || MATERIAL_SHADINGMODEL_HAIR || MATERIAL_SHADINGMODEL_CLOTH || MATERIAL_SHADINGMODEL_EYE || MATERIAL_SHADINGMODEL_TOON))
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
## DeferredShadingCommon.ush
Path: `Shaders/Private/DeferredShadingCommon.ush`
如有新增GBuffer Slot,擴充`Texture2D`等#define定義
```cpp
Texture2D GBufferFTexture;
// [Toon][Modified begin] @cc5568135
Texture2D GBufferGTexture;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
Texture2D<uint> SceneLightingChannels;
...
#define GBufferFTextureSampler GlobalPointClampedSampler
// [Toon][Modified begin] @cc5568135
#define GBufferGTextureSampler GlobalPointClampedSampler
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
#define GBufferVelocityTextureSampler GlobalPointClampedSampler
```
擴充`HasCustomGBufferData`
```cpp
...
|| ShadingModelID == SHADINGMODELID_CLOTH
// [Toon][Add-Begin] @cc5568135 - Toon
|| ShadingModelID == SHADINGMODELID_TOON
// [Toon][Add-End] @cc5568135 2024/10/26
|| ShadingModelID == SHADINGMODELID_EYE;
```
擴充`FGBufferData`
```cpp
...
// Curvature for mobile subsurface profile
half Curvature;
// [Toon][Add-Begin] @cc5568135 - Toon
// 0..1, only needed by SHADINGMODELID_TOON
half3 ShadowColor;
// 0..1, only needed by SHADINGMODELID_TOON
half3 FaceForwardVector;
// [Toon][Add-End] @cc5568135 2024/10/26
};
```
擴充`EncodeGBuffer`,如有新增GBuffer Slot 可以自行調整內容
```cpp
out float4 OutGBufferE,
// [Toon][Modified begin] @cc5568135
out float4 OutGBufferG,
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
out float4 OutGBufferVelocity,
```
*裡面的內容,再UE5已由自動生成的Code替代。所以可以不用管。*
```cpp
if (GBuffer.ShadingModelID == SHADINGMODELID_UNLIT)
{
OutGBufferA = 0;
SetGBufferForUnlit(OutGBufferB);
OutGBufferC = 0;
OutGBufferD = 0;
OutGBufferE = 0;
// [Toon][Modified begin] @cc5568135
OutGBufferG = 0;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
...
OutGBufferE = GBuffer.PrecomputedShadowFactors;
// [Toon][Modified begin] @cc5568135
if (GBuffer.ShadingModelID != SHADINGMODELID_TOON)
{
OutGBufferG = 0;
}
else
{
OutGBufferG.rgb = GBuffer.ShadowColor.rgb;
OutGBufferG.a = GBuffer.FaceForwardVector.z;
}
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
擴充`DecodeGBufferData`,如有新增GBuffer Slot 可以自行調整內容。
*裡面的內容,再UE5已由自動生成的Code替代。所以可以不用管。*
```cpp
float4 InGBufferF,
// [Toon][Modified begin] @cc5568135
float4 InGBufferG,
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
float4 InGBufferVelocity,
```
```cpp
GBuffer.BaseColor = DecodeBaseColor(InGBufferC.rgb);
// [Toon][Modified begin] @cc5568135
GBuffer.ShadowColor = 0;
...
// [Toon][Modified end] @cc5568135 Last modified 2025/05/05
```
修改`return DecodeGBufferData`符合新input格式,有3處。
```cpp
float SceneDepth = CalcSceneDepth(PixelPos);
// [Toon][Modified begin] @cc5568135
float4 GBufferG = SceneTexturesStruct.GBufferGTexture.Load(int3(PixelPos, 0));
//return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromPixelPos(PixelPos));
return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferG, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromPixelPos(PixelPos));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
```cpp
float4 GBufferF = GBufferFTexture.SampleLevel(GBufferFTextureSampler, UV, 0);
// [Toon][Modified begin] @cc5568135
float4 GBufferG = GBufferGTexture.SampleLevel(GBufferGTextureSampler, UV, 0);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
...
float DeviceZ = SampleDeviceZFromSceneTextures(UV);
float SceneDepth = ConvertFromDeviceZ(DeviceZ);
// [Toon][Modified begin] @cc5568135
// return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV));
return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferG, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
```cpp
float SceneDepth = CalcSceneDepth(UV);
// [Toon][Modified begin] @cc5568135
float4 GBufferG = Texture2DSampleLevel(SceneTexturesStruct.GBufferGTexture, SceneTexturesStruct_GBufferGTextureSampler, UV, 0);
// return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV));
return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferG, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
## BasePassPixelShader.usf
Path: `Shaders/Private/BasePassPixelShader.usf`
擴充`FPixelShaderInOut_MainPS`
```cpp
// 0..1, SubsurfaceProfileId = int(x * 255)
float SubsurfaceProfile = 0;
// [Toon][Add-Begin] @cc5568135 - Toon
float3 ShadowColor = GetMaterialShadowColor(PixelMaterialInputs);
float3 FaceForwardVector = GetMaterialFaceForwardVector(PixelMaterialInputs);
// [Toon][Add-End] @cc5568135 2024/10/26
```
擴充`SetGBufferForShadingModel`
這裡設定來自Material系統的參數數值,要插入的Gbuffer slot位置。
```cpp
Dither,
// [Toon][Add-Begin] @cc5568135 - Toon
ShadowColor,
FaceForwardVector,
// [Toon][Add-End] @cc5568135 2024/10/26
ShadingModel
);
```
在設定 Out.MRT 之前,替換 GBuffer 參數位置。
```cpp
#if USES_GBUFFER
// -0.5 .. 0.5, could be optimzed as lower quality noise would be sufficient
float QuantizationBias = PseudoRandom( MaterialParameters.SvPosition.xy ) - 0.5f;
GBuffer.IndirectIrradiance = IndirectIrradiance;
// [Toon][Modified begin] @cc5568135
#if MATERIAL_SHADINGMODEL_TOON
if (GBuffer.ShadingModelID == SHADINGMODELID_TOON)
{
GBuffer.CustomData.rgb = GBuffer.FaceShadowTexture.rgb;
GBuffer.PrecomputedShadowFactors.rg = GBuffer.FaceForwardVector.xy;
GBuffer.PrecomputedShadowFactors.ba = GBuffer.FaceRightwardVector.xy;
GBuffer.ShadowColor.rgb = GBuffer.ShadowColor.rgb;
}
#endif
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
```
若有擴充 GBuffer slot, 新增 `GBufferG` 相關
```cpp
// PreShadowFactor
float4 OutGBufferE = 0;
// [Toon][Modified begin] @cc5568135
float4 OutGBufferG = 0;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
...
float4 OutGBufferB = 0;
float4 OutGBufferC = 0;
// [Toon][Modified begin] @cc5568135
//EncodeGBuffer(GBuffer, OutGBufferA, OutGBufferB, OutGBufferC, OutGBufferD, OutGBufferE, OutVelocity, QuantizationBias);
float4 OutGBufferG = 0;
EncodeGBuffer(GBuffer, OutGBufferA, OutGBufferB, OutGBufferC, OutGBufferD, OutGBufferE, OutGBufferG, OutVelocity, QuantizationBias);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
...
#if GBUFFER_HAS_PRECSHADOWFACTOR
Out.MRT[GBUFFER_HAS_VELOCITY ? 6 : 5] = OutGBufferE;
#endif
// [Toon][Modified begin] @cc5568135
Out.MRT[6] = OutGBufferG;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
```
## ShaderOutputCommon.ush
Path`Shaders\Private\ShaderOutputCommon.ush`
如有新增GBuffer Slot,新增`PIXELSHADEROUTPUT_MRT8`定義
```cpp
#ifndef PIXELSHADEROUTPUT_MRT7
#define PIXELSHADEROUTPUT_MRT7 0
#endif
// [Toon][Modified begin] @cc5568135
#ifndef PIXELSHADEROUTPUT_MRT8
#define PIXELSHADEROUTPUT_MRT8 0
#endif
// [Toon][Modified end] @cc5568135 Last modified 2025/05/08
```
## PixelShaderOutputCommon.ush
Path `Shaders\Private\PixelShaderOutputCommon.ush`
如有新增GBuffer Slot,新增 `OutTarget8`
```cpp
#if PIXELSHADEROUTPUT_MRT7
, out float4 OutTarget7 : SV_Target7
#endif
// [Toon][Modified begin] @cc5568135
#if PIXELSHADEROUTPUT_MRT8
, out float4 OutTarget8 : SV_Target8
#endif
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
...
#if PIXELSHADEROUTPUT_MRT7
OutTarget7 = PixelShaderOut.MRT[7];
#endif
// [Toon][Modified begin] @cc5568135
#if PIXELSHADEROUTPUT_MRT8
OutTarget8 = PixelShaderOut.MRT[8];
#endif
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
```
## SSDCommon.ush
Path `Shaders\Private\ScreenSpaceDenoise\SSDCommon.ush`
如有新增GBuffer Slot,新增 `GBufferG` 參數並修改 `DecodeGBufferData`
```cpp
float4 GBufferF = 0.5f;
// [Toon][Modified begin] @cc5568135
float4 GBufferG = 0.0;
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
float4 GBufferVelocity = 0.0;
...
// [Toon][Modified begin] @cc5568135
//GBufferData = DecodeGBufferData(
// GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity,
// CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(BufferUV));
GBufferData = DecodeGBufferData(
GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferG, GBufferVelocity,
CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(BufferUV));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
```
## ShadingModelsMaterial.ush
Path: `Shaders/Private/ShadingModelsMaterial.ush`
這個Function可以修改GBuffer對每個MSM的數值。
擴充`SetGBufferForShadingModel`, Inputs & 後方要設定GBuffer。
```cpp
...
const float Dither,
// [Toon][Add-Begin] @cc5568135 - Toon
const float3 ShadowColor,
const float3 FaceForwardVector,
// [Toon][Add-End] @cc5568135 2024/10/26
const uint ShadingModel)
...
// [Toon][Modified begin] @cc5568135
#if MATERIAL_SHADINGMODEL_TOON
else if (ShadingModel == SHADINGMODELID_TOON){
GBuffer.ShadowColor = ShadowColor;
GBuffer.FaceForwardVector = FaceForwardVector;
}
#endif
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
#if MATERIAL_SHADINGMODEL_EYE
```
## GBufferHelpers.ush
GBufferPostDecode 可以修改gbuffer後解碼的內容
## ShadingModels.ush
Path: `Shaders/Private/ShadingModels.ush`
在這裡可以調整或是新增BxDF
修改`IntegrateBxDF`設定新MSM跑自訂的BxDF
```cpp
...
case SHADINGMODELID_EYE:
return EyeBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
// [Toon][Add-Begin] @cc5568135 - Toon
case SHADINGMODELID_TOON:
return ToonBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
// [Toon][Add-End] @cc5568135 2024/10/26
default:
return (FDirectLighting)0;
...
```
## RayTracingDeferredShadingCommon.ush
Path `Shaders\Private\RayTracing\RayTracingDeferredShadingCommon.ush`
如有新增GBuffer Slot,修改`GetGBufferDataFromSceneTexturesLoad`內容。
```cpp
float4 GBufferF = GBufferFTexture.Load(int3(PixelCoord, 0));
// [Toon][Modified begin] @cc5568135
float4 GBufferG = GBufferGTexture.Load(int3(PixelCoord, 0));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
...
// [Toon][Modified begin] @cc5568135
// return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromPixelPos(PixelCoord));
return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferG, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromPixelPos(PixelCoord));
// [Toon][Modified end] @cc5568135 Last modified 2025/05/09
```
## ShadingModelsSampling.ush
Path: `Engine/Shaders/Private/ShadingModelsSampling.ush`
Path tracing & Ray tracing sampling相關, 例如計算取樣的PDF等
可以不用加東西
## ReflectionEnvironmentPixelShader.usf
`Shaders/Private/ReflectionEnvironmentPixelShader.usf`
可在這裡調整各個MSM的反射Function。
例如Toon不要有反射:
```cpp
// [Toon][Modify-Begin] @cc5568135 - No Reflection for Toon
//const bool bUnlitMaterial = ShadingModelID == SHADINGMODELID_UNLIT;
const bool bUnlitMaterial = ShadingModelID == SHADINGMODELID_UNLIT || ShadingModelID == SHADINGMODELID_TOON;
// [Toon][Modify-End] @cc5568135 2024/10/24
```
## ClusteredDeferredShadingPixelShader.usf
Path: `Engine/Shaders/Private/ClusteredDeferredShadingPixelShader.usf`
擴充`#if USE_PASS_PER_SHADING_MODEL`下面內容
```cpp
// [Toon][Modified begin] @cc5568135
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_TOON, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridHeader, Dither, FirstNonSimpleLightIndex);
// [Toon][Modified end] @cc5568135 Last modified 2025/05/03
```
## DeferredLightingCommon.ush
修改`GetDynamicLightingSplit`可以讓不同SM用不同的光照Function
```cpp
// [Toon][Modify-Add] @cc5568135 - Toon
if (GBuffer.ShadingModelID == SHADINGMODELID_TOON)
{
FLightAccumulator LightAccumulator = AccumulateToonLighting(TranslatedWorldPosition, CameraVector, GBuffer, AmbientOcclusion, LightData, LightAttenuation, Dither, SVPos, SurfaceShadow);
return LightAccumulator_GetResultSplit(LightAccumulator);
}
// [Toon][Modify-End] @cc5568135 2024/10/28
FLightAccumulator LightAccumulator = AccumulateDynamicLighting(TranslatedWorldPosition, CameraVector, GBuffer, AmbientOcclusion, LightData, LightAttenuation, Dither, SVPos, SurfaceShadow);
return LightAccumulator_GetResultSplit(LightAccumulator);
```
## TODO Lumen & PT & others
`Engine/Shaders/Private/Lumen/LumenMaterial.ush`
`Engine/Shaders/Private/PathTracing/...`
`Engine\Shaders\Private\RayTracing\...`
# 其他
## Enable ShaderDevelopmentMode
在`...\Engine\Config\ConsoleVariables.ini`檔案中可以啟用`r.ShaderDevelopmentMode=1`。
啟用後在Compile shader階段引擎會顯示詳細error資訊,幫助開發Unreal shader。
```ini
; Uncomment to get detailed logs on shader compiles and the opportunity to retry on errors, and enable showing shader warnings
r.ShaderDevelopmentMode=1
```
`r.DumpShaderDebugInfo`可以調整Dump shaders 內容
預設狀況下,有問題的.ush .usf 會自訂複製一份到 `\Saved\ShaderDebugInfo\PCD3D_SM6` (Engine 或 Project都會有),不過不會自動刪除,記得手動去刪掉避免因為歷史紀錄而誤判。
---
---
# References
UE5でつくるセルシェーディング 第4-6回
https://cgworld.jp/regular/unreal_engine/
【UE5 渲染管线篇】素描风格渲染管线实现:(2)添加光照模型与材质接口 https://zhuanlan.zhihu.com/p/680177835
UE5新增Toon管线实践
https://zhuanlan.zhihu.com/p/647312365
Adding a new Shading Model in Unreal5
https://neozheng.cn/2022/08/14/Adding%20a%20new%20Shading%20Model/
[写一个自己的移动端shading model!](https://blog.csdn.net/weixin_43369654/article/details/116149833?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-8-116149833-blog-82990302.235^v43^pc_blog_bottom_relevance_base7&spm=1001.2101.3001.4242.5&utm_relevant_index=11)