1. 在 EngineTypes.h 中添加新的模型枚举
假设新的模型名称为 MercuryToon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
UENUM()
enum EMaterialShadingModel : int
{
MSM_Unlit UMETA(DisplayName="Unlit"),
MSM_DefaultLit UMETA(DisplayName="Default Lit"),
MSM_Subsurface UMETA(DisplayName="Subsurface"),
MSM_PreintegratedSkin UMETA(DisplayName="Preintegrated Skin"),
MSM_ClearCoat UMETA(DisplayName="Clear Coat"),
MSM_SubsurfaceProfile UMETA(DisplayName="Subsurface Profile"),
MSM_TwoSidedFoliage UMETA(DisplayName="Two Sided Foliage"),
MSM_Hair UMETA(DisplayName="Hair"),
MSM_Cloth UMETA(DisplayName="Cloth"),
MSM_Eye UMETA(DisplayName="Eye"),
MSM_SingleLayerWater UMETA(DisplayName="SingleLayerWater"),
MSM_ThinTranslucent UMETA(DisplayName="Thin Translucent"),
MSM_Strata UMETA(DisplayName="Substrate", Hidden),
// BEGIN Engine Change [Shading Model]: Adding a new shading model enum
MSM_MercuryToon UMETA(DisplayName="MercuryToon"),
// END Engine Change
/** Number of unique shading models. */
MSM_NUM UMETA(Hidden),
/** Shading model will be determined by the Material Expression Graph,
by utilizing the 'Shading Model' MaterialAttribute output pin. */
MSM_FromMaterialExpression UMETA(DisplayName="From Material Expression"),
MSM_MAX
};
2. 在 MaterialExpressionShadingModel.h 中添加新的模型枚举选项
在 UPROPERTY 中添加 MSM_MercuryToon
1
2
UPROPERTY(EditAnywhere, Category=ShadingModel, meta=(ValidEnumValues="MSM_DefaultLit, MSM_Subsurface, MSM_PreintegratedSkin, MSM_ClearCoat, MSM_SubsurfaceProfile, MSM_TwoSidedFoliage, MSM_Hair, MSM_Cloth, MSM_Eye, MSM_MercuryToon", ShowAsInputPin = "Primary"))
TEnumAsByte<enum EMaterialShadingModel> ShadingModel = MSM_DefaultLit;
3. 在 MaterialShader.cpp 中添加着色模型到字符串的转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/** Converts an EMaterialShadingModel to a string description. */
FString GetShadingModelString(EMaterialShadingModel ShadingModel)
{
FString ShadingModelName;
switch(ShadingModel)
{
case MSM_Unlit: ShadingModelName = TEXT("MSM_Unlit"); break;
case MSM_DefaultLit: ShadingModelName = TEXT("MSM_DefaultLit"); break;
case MSM_Subsurface: ShadingModelName = TEXT("MSM_Subsurface"); break;
case MSM_PreintegratedSkin: ShadingModelName = TEXT("MSM_PreintegratedSkin"); break;
case MSM_ClearCoat: ShadingModelName = TEXT("MSM_ClearCoat"); break;
case MSM_SubsurfaceProfile: ShadingModelName = TEXT("MSM_SubsurfaceProfile"); break;
case MSM_TwoSidedFoliage: ShadingModelName = TEXT("MSM_TwoSidedFoliage"); break;
case MSM_Hair: ShadingModelName = TEXT("MSM_Hair"); break;
case MSM_Cloth: ShadingModelName = TEXT("MSM_Cloth"); break;
case MSM_Eye: ShadingModelName = TEXT("MSM_Eye"); break;
case MSM_SingleLayerWater: ShadingModelName = TEXT("MSM_SingleLayerWater"); break;
case MSM_ThinTranslucent: ShadingModelName = TEXT("MSM_ThinTranslucent"); break;
// Mercury Toon Begin
case MSM_MercuryToon: ShadingModelName = TEXT("MSM_MercuryToon"); break;
// Mercury Toon End
default: ShadingModelName = TEXT("Unknown"); break;
}
return ShadingModelName;
}
4. 在 MaterialShader.cpp 将着色模型设置为光照(Lit)模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void UpdateMaterialShaderCompilingStats(const FMaterial* Material)
{
// ...
FMaterialShadingModelField ShadingModels = Material->GetShadingModels();
if (ShadingModels.HasOnlyShadingModel(MSM_Unlit))
{
INC_DWORD_STAT_BY(STAT_ShaderCompiling_NumUnlitMaterialShaders, 1);
}
// Mercury Toon Begin
else if (ShadingModels.HasAnyShadingModel({ MSM_DefaultLit, MSM_Subsurface, MSM_PreintegratedSkin, MSM_ClearCoat, MSM_Cloth, MSM_SubsurfaceProfile, MSM_TwoSidedFoliage, MSM_SingleLayerWater, MSM_ThinTranslucent, MSM_MercuryToon }))
// Mercury Toon End
{
INC_DWORD_STAT_BY(STAT_ShaderCompiling_NumLitMaterialShaders, 1);
}
// ...
}
5. 在 ShderMaterial.h 中添加 shading model 定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct FShaderMaterialPropertyDefines
{
//DECLARE_TYPE_LAYOUT(FShaderMaterialPropertyDefines, NonVirtual);
//void ModifyEnvironment(FShaderCompilerEnvironment& OutEnvironment) const; //void WriteFrozenVertexFactoryParameters(FMemoryImageWriter& Writer, const TMemoryImagePtr<FShaderMaterialPropertyDefines>& InPropDefines) const;
uint8 MATERIAL_ENABLE_TRANSLUCENCY_FOGGING : 1;
uint8 MATERIALBLENDING_ANY_TRANSLUCENT : 1;
uint8 MATERIAL_USES_SCENE_COLOR_COPY : 1;
uint8 MATERIALBLENDING_MASKED_USING_COVERAGE : 1;
uint8 MATERIAL_COMPUTE_FOG_PER_PIXEL : 1;
uint8 MATERIAL_SHADINGMODEL_UNLIT : 1;
uint8 MATERIAL_SHADINGMODEL_DEFAULT_LIT : 1;
uint8 MATERIAL_SHADINGMODEL_SUBSURFACE : 1;
uint8 MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN : 1;
uint8 MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE : 1;
uint8 MATERIAL_SHADINGMODEL_CLEAR_COAT : 1;
uint8 MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE : 1;
uint8 MATERIAL_SHADINGMODEL_HAIR : 1;
uint8 MATERIAL_SHADINGMODEL_CLOTH : 1;
uint8 MATERIAL_SHADINGMODEL_EYE : 1;
uint8 MATERIAL_SHADINGMODEL_SINGLELAYERWATER : 1;
uint8 SINGLE_LAYER_WATER_SEPARATED_MAIN_LIGHT : 1;
uint8 MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT : 1;
// Mercury Toon Begin
uint8 MATERIAL_SHADINGMODEL_MERCURY_TOON : 1;
// Mercury Toon End
//...
}
6. 在 HLSLMaterialTranslator.cpp 中的 GetMaterialEnvironment 添加 shading model 环境定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void FHLSLMaterialTranslator::GetMaterialEnvironment(EShaderPlatform InPlatform, FShaderCompilerEnvironment& OutEnvironment)
{
if (EnvironmentDefines->bShadingModelsIsLit)
{
if (EnvironmentDefines->HasShadingModel(MSM_DefaultLit))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_DEFAULT_LIT"), TEXT("1"));
}
// Mercury Toon Begin
if (EnvironmentDefines->HasShadingModel(MSM_MercuryToon))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_MERCURY_TOON"), TEXT("1"));
}// Mercury Toon End
}
}
7. ShaderGenerationUtil.cpp
7.1 ApplyFetchEnvironmentInternal
添加我们的着色器相关指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template<typename ContainerType>
void ApplyFetchEnvironmentInternal(FShaderMaterialPropertyDefines& SrcDefines, const ContainerType& Container)
{
FETCH_COMPILE_BOOL(MATERIAL_ENABLE_TRANSLUCENCY_FOGGING);
FETCH_COMPILE_BOOL(MATERIALBLENDING_ANY_TRANSLUCENT);
FETCH_COMPILE_BOOL(MATERIAL_USES_SCENE_COLOR_COPY);
FETCH_COMPILE_BOOL(MATERIALBLENDING_MASKED_USING_COVERAGE);
FETCH_COMPILE_BOOL(MATERIAL_COMPUTE_FOG_PER_PIXEL);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_UNLIT);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_DEFAULT_LIT);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_SUBSURFACE);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_CLEAR_COAT);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_HAIR);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_CLOTH);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_EYE);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_SINGLELAYERWATER);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT);
// Mercury Toon Begin
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_MERCURY_TOON);
// Mercury Toon End
// rest
}
7.2 SetSlotsForShadingModelType
设置我们的着色器 GBuffer Slot (不太确定有没有用,并且目前只是直接设置与 Unilt 模型相同的值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// If we are storing writing to the GBuffer, what slots does this shading model write? Ignores the other forward-shading effects
// like the dual blending of ThinTranslucent or fogging.
// If we are going one GBuffer for all shader model formats, then we treat all custom data as a single RGBA8 value (bMergeCustom=true). But
// if each shading model has a unique GBuffer format, we set it to false to pack each format as tightly as possible.
static void SetSlotsForShadingModelType(bool Slots[], EMaterialShadingModel ShadingModel, bool bMergeCustom)
{
switch (ShadingModel)
{
// Mercury Toon Begin
case MSM_MercuryToon:
// Mercury Toon End
case MSM_Unlit:
Slots[GBS_SceneColor] = true;
break;
// Rest
}
7.3 DetermineUsedMaterialSlots
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static void DetermineUsedMaterialSlots(
EGBufferSlotUsage Slots[GBS_Num],
const FShaderMaterialDerivedDefines& Dst,
const FShaderMaterialPropertyDefines& Mat,
const FShaderLightmapPropertyDefines& Lightmap,
const FShaderGlobalDefines& SrcGlobal,
const FShaderCompilerDefines& Compiler,
ERHIFeatureLevel::Type FEATURE_LEVEL)
{
bool bWriteEmissive = Dst.NEEDS_BASEPASS_VERTEX_FOGGING || Mat.USES_EMISSIVE_COLOR || SrcGlobal.ALLOW_STATIC_LIGHTING || Mat.MATERIAL_SHADINGMODEL_SINGLELAYERWATER;
bool bHasTangent = SrcGlobal.GBUFFER_HAS_TANGENT;
bool bHasVelocity = SrcGlobal.GBUFFER_HAS_VELOCITY;
bool bWritesVelocity = Dst.WRITES_VELOCITY_TO_GBUFFER;
bool bHasStaticLighting = Dst.GBUFFER_HAS_PRECSHADOWFACTOR || Dst.WRITES_PRECSHADOWFACTOR_TO_GBUFFER;
bool bIsSubstrateMaterial = Mat.SUBSTRATE_ENABLED; // Similarly to FetchFullGBufferInfo, we do not check for MATERIAL_IS_SUBSTRATE as this is decided per project.
// Substrate doesn't use gbuffer, and thus doesn't need CustomData
const bool bUseCustomData = !bIsSubstrateMaterial;
// we have to use if statements, not switch or if/else statements because we can have multiple shader model ids.
if (Mat.MATERIAL_SHADINGMODEL_UNLIT)
{
SetStandardGBufferSlots(Slots, true, false, bHasVelocity, bWritesVelocity, false, bIsSubstrateMaterial);
}
// Mercury Toon Begin: Setting the GBuffer slots used by our shading model and other configurations (copying emissive but with some changes). Forward rendering tho so this won't actually be called for us but might as well
if (Mat.MATERIAL_SHADINGMODEL_LIGHTSMUGGLER)
{
SetStandardGBufferSlots(Slots, true, false, bHasVelocity, bWritesVelocity, bHasStaticLighting, bIsSubstrateMaterial);
}
// Mercury Toon End
// Rest
}
8. Definitions.usf
1
2
3
4
5
// Mercury Toon Begin: Adding our shading model define, if it wasn't set from the HLSL Material translator, we set it to 0
#ifndef MATERIAL_SHADINGMODEL_LIGHTSMUGGLER
#define MATERIAL_SHADINGMODEL_LIGHTSMUGGLER 0
#endif
// Mercury Toon End
9. ShadingCommon.ush
9.1 Shading Model ID Declaration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
///////////////////////////////////////////////////////////////////////////////
// Shading models
// SHADINGMODELID_* occupy the 4 low bits of an 8bit channel and SKIP_* occupy the 4 high bits
#define SHADINGMODELID_UNLIT 0
#define SHADINGMODELID_DEFAULT_LIT 1
#define SHADINGMODELID_SUBSURFACE 2
#define SHADINGMODELID_PREINTEGRATED_SKIN 3
#define SHADINGMODELID_CLEAR_COAT 4
#define SHADINGMODELID_SUBSURFACE_PROFILE 5
#define SHADINGMODELID_TWOSIDED_FOLIAGE 6
#define SHADINGMODELID_HAIR 7
#define SHADINGMODELID_CLOTH 8
#define SHADINGMODELID_EYE 9
#define SHADINGMODELID_SINGLELAYERWATER 10
#define SHADINGMODELID_THIN_TRANSLUCENT 11
#define SHADINGMODELID_SUBSTRATE 12 // Temporary while we convert everything to Substrate
// Mercury Toon Begin
#define SHADINGMODELID_MERCURY_TOON 13
#define SHADINGMODELID_NUM 14
// Mercury Toon End
#define SHADINGMODELID_MASK 0xF // 4 bits reserved for ShadingModelID
9.2 GetShadingModelColor
给我们的着色模型定一个用于 Debug 显示的颜色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// for debugging and to visualize
float3 GetShadingModelColor(uint ShadingModelID)
{
// TODO: PS4 doesn't optimize out correctly the switch(), so it thinks it needs all the Samplers even if they get compiled out
// This will get fixed after launch per Sony...
#if PS4_PROFILE
if (ShadingModelID == SHADINGMODELID_UNLIT) return float3(0.1f, 0.1f, 0.2f); // Dark Blue
else if (ShadingModelID == SHADINGMODELID_DEFAULT_LIT) return float3(0.1f, 1.0f, 0.1f); // Green
else if (ShadingModelID == SHADINGMODELID_SUBSURFACE) return float3(1.0f, 0.1f, 0.1f); // Red
else if (ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN) return float3(0.6f, 0.4f, 0.1f); // Brown
else if (ShadingModelID == SHADINGMODELID_CLEAR_COAT) return float3(0.1f, 0.4f, 0.4f);
else if (ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE) return float3(0.2f, 0.6f, 0.5f); // Cyan
else if (ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE) return float3(0.2f, 0.2f, 0.8f); // Blue
else if (ShadingModelID == SHADINGMODELID_HAIR) return float3(0.6f, 0.1f, 0.5f);
else if (ShadingModelID == SHADINGMODELID_CLOTH) return float3(0.7f, 1.0f, 1.0f);
else if (ShadingModelID == SHADINGMODELID_EYE) return float3(0.3f, 1.0f, 1.0f);
else if (ShadingModelID == SHADINGMODELID_SINGLELAYERWATER) return float3(0.5f, 0.5f, 1.0f);
else if (ShadingModelID == SHADINGMODELID_THIN_TRANSLUCENT) return float3(1.0f, 0.8f, 0.3f);
else if (ShadingModelID == SHADINGMODELID_SUBSTRATE) return float3(1.0f, 1.0f, 0.0f);
// Mercury Toon Begin
else if (ShadingModelID == SHADINGMODELID_Mercury_Toon) return float3(0.7f, 0.1f, 0.9f); // Purplish
// Mercury Toon END
else return float3(1.0f, 1.0f, 1.0f); // White
#else
switch(ShadingModelID)
{
case SHADINGMODELID_UNLIT: return float3(0.1f, 0.1f, 0.2f); // Dark Blue
case SHADINGMODELID_DEFAULT_LIT: return float3(0.1f, 1.0f, 0.1f); // Green
case SHADINGMODELID_SUBSURFACE: return float3(1.0f, 0.1f, 0.1f); // Red
case SHADINGMODELID_PREINTEGRATED_SKIN: return float3(0.6f, 0.4f, 0.1f); // Brown
case SHADINGMODELID_CLEAR_COAT: return float3(0.1f, 0.4f, 0.4f); // Brown
case SHADINGMODELID_SUBSURFACE_PROFILE: return float3(0.2f, 0.6f, 0.5f); // Cyan
case SHADINGMODELID_TWOSIDED_FOLIAGE: return float3(0.2f, 0.2f, 0.8f); // Cyan
case SHADINGMODELID_HAIR: return float3(0.6f, 0.1f, 0.5f);
case SHADINGMODELID_CLOTH: return float3(0.7f, 1.0f, 1.0f);
case SHADINGMODELID_EYE: return float3(0.3f, 1.0f, 1.0f);
case SHADINGMODELID_SINGLELAYERWATER: return float3(0.5f, 0.5f, 1.0f);
case SHADINGMODELID_THIN_TRANSLUCENT: return float3(1.0f, 0.8f, 0.3f);
case SHADINGMODELID_SUBSTRATE: return float3(1.0f, 1.0f, 0.0f);
// Mercury Toon Begin
case SHADINGMODELID_Mercury_Toon: return float3(0.7f, 0.1f, 0.9f); // Purplish
// Mercury Toon END
default: return float3(1.0f, 1.0f, 1.0f); // White
}
#endif
}
10. ClusteredDeferredShadingPixelShader.usf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/ Prior
// Regular lights
#if USE_PASS_PER_SHADING_MODEL
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_DEFAULT_LIT, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SUBSURFACE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_PREINTEGRATED_SKIN, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_CLEAR_COAT, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SUBSURFACE_PROFILE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_TWOSIDED_FOLIAGE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_HAIR, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_CLOTH, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_EYE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SINGLELAYERWATER, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
// Mercury Toon Begin
GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_LIGHTSMUGGLER, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
// Mercury Toon END
// SHADINGMODELID_THIN_TRANSLUCENT - skipping because it can not be opaque
#else // !USE_PASS_PER_SHADING_MODEL
CompositedLighting += GetLightGridLocalLighting(GetScreenSpaceData(ScreenUV), CulledLightGridData, TranslatedWorldPosition, CameraVector, ScreenUV, SceneDepth, 0, Dither, FirstNonSimpleLightIndex);
#endif // USE_PASS_PER_SHADING_MODEL
// Rest
This post is licensed under CC BY 4.0 by the author.