参考文章:UE5自定义着色模型 Unreal Engine 5 custom Shading Model - 知乎
主要记录修改位置,方便在5.2 或者更高版本创建。
Engine\Shaders\Private\DeferredShadingCommon.ush
bool HasCustomGBufferData(int ShadingModelID)
{
return ShadingModelID == SHADINGMODELID_SUBSURFACE
|| ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN
|| ShadingModelID == SHADINGMODELID_CLEAR_COAT
|| ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE
|| ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE
|| ShadingModelID == SHADINGMODELID_HAIR
|| ShadingModelID == SHADINGMODELID_CLOTH
|| ShadingModelID == SHADINGMODELID_EYE
|| ShadingModelID == SHADINGMODELID_KOOENGINE;
}
Engine\Shaders\Private\Definitions.usf
#ifndef MATERIAL_SHADINGMODEL_SUBSURFACE
#define MATERIAL_SHADINGMODEL_SUBSURFACE 0
#endif
#ifndef MATERIAL_SHADINGMODEL_KOOENGINE
#define MATERIAL_SHADINGMODEL_KOOENGINE 0
#endif
Engine\Shaders\Private\ShadingCommon.ush
// 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_KOOENGINE 12
#define SHADINGMODELID_STRATA 13 // Temporary while we convert everything to Strata
#define SHADINGMODELID_NUM 14
#define SHADINGMODELID_MASK 0xF // 4 bits reserved for ShadingModelID
// 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_KOOENGINE) return float3(1.0f, 0.0f, 0.0f);
else if (ShadingModelID == SHADINGMODELID_STRATA) return float3(1.0f, 1.0f, 0.0f);
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_KOOENGINE: return float3(1.0f, 0.0f, 0.0f);
case SHADINGMODELID_STRATA: return float3(1.0f, 1.0f, 0.0f);
default: return float3(1.0f, 1.0f, 1.0f); // White
}
#endif
}
Engine\Shaders\Private\ShadingModelsMaterial.ush
#if MATERIAL_SHADINGMODEL_EYE
else if (ShadingModel == SHADINGMODELID_EYE)
{
const float IrisMask = saturate(GetMaterialCustomData0(MaterialParameters));
const float IrisDistance = saturate(GetMaterialCustomData1(MaterialParameters));
GBuffer.CustomData.x = EncodeSubsurfaceProfile(SubsurfaceProfile).x;
GBuffer.CustomData.w = 1.0f - IrisMask; // Opacity
#if IRIS_NORMAL
float2 WorldNormalOct = UnitVectorToOctahedron( GBuffer.WorldNormal );
// CausticNormal stored as octahedron
#if NUM_MATERIAL_OUTPUTS_GETTANGENTOUTPUT > 0
// Blend in the negative intersection normal to create some concavity
// Not great as it ties the concavity to the convexity of the cornea surface
// No good justification for that. On the other hand, if we're just looking to
// introduce some concavity, this does the job.
float3 PlaneNormal = normalize( GetTangentOutput0(MaterialParameters) );
float3 CausticNormal = normalize( lerp( PlaneNormal, -GBuffer.WorldNormal, IrisMask*IrisDistance ) );
float2 CausticNormalOct = UnitVectorToOctahedron( CausticNormal );
float2 CausticNormalDelta = ( CausticNormalOct - WorldNormalOct ) * 0.5 + (128.0/255.0);
GBuffer.Metallic = CausticNormalDelta.x;
GBuffer.Specular = CausticNormalDelta.y;
#else
float3 PlaneNormal = GBuffer.WorldNormal;
GBuffer.Metallic = 128.0/255.0;
GBuffer.Specular = 128.0/255.0;
#endif
// IrisNormal CustomData.yz
#if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0
float3 IrisNormal = normalize( ClearCoatBottomNormal0(MaterialParameters) );
#if MATERIAL_TANGENTSPACENORMAL
IrisNormal = normalize( TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, IrisNormal ) );
#endif
#else
float3 IrisNormal = PlaneNormal;
#endif
float2 IrisNormalOct = UnitVectorToOctahedron( IrisNormal );
float2 IrisNormalDelta = ( IrisNormalOct - WorldNormalOct ) * 0.5 + (128.0/255.0);
GBuffer.CustomData.yz = IrisNormalDelta;
#else
GBuffer.Metallic = IrisDistance;
#if NUM_MATERIAL_OUTPUTS_GETTANGENTOUTPUT > 0
float3 Tangent = GetTangentOutput0(MaterialParameters);
GBuffer.CustomData.yz = UnitVectorToOctahedron( normalize(Tangent) ) * 0.5 + 0.5;
#endif
#endif
#if SHADING_PATH_MOBILE
#if MATERIAL_SHADINGMODEL_EYE_USE_CURVATURE
GBuffer.Curvature = Metallic;
#else
GBuffer.Curvature = CalculateCurvature(GBuffer.WorldNormal, MaterialParameters.WorldPosition_CamRelative);
#endif
GBuffer.Curvature = clamp(GBuffer.Curvature, 0.001f, 1.0f);
#endif
}
#endif
#if MATERIAL_SHADINGMODEL_KOOENGINE
else if (ShadingModel == SHADINGMODELID_KOOENGINE)
{
GBuffer.CustomData.x = saturate( GetMaterialCustomData0(MaterialParameters) );
GBuffer.CustomData.y = saturate( GetMaterialCustomData1(MaterialParameters) );
GBuffer.CustomData.z = 0.0f;
GBuffer.CustomData.w = 0.0f;
}
#endif
Engine\Source\Runtime\Engine\Classes\Engine\EngineTypes.h
/**
* Specifies the overal rendering/shading model for a material
* @warning Check UMaterialInstance::Serialize if changed!
*/
UENUM()
enum EMaterialShadingModel
{
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_KooEngine UMETA(DisplayName="KooEngine"),
MSM_Strata UMETA(DisplayName="Strata", Hidden),
/** 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
};
Engine\Source\Runtime\Engine\Private\Materials\HLSLMaterialTranslator.cpp
if (ShadingModels.HasShadingModel(MSM_ThinTranslucent))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT"), TEXT("1"));
NumSetMaterials++;
bMaterialRequestsDualSourceBlending = true;
}
if (ShadingModels.HasShadingModel(MSM_KooEngine))
{
OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_KOOENGINE"), TEXT("1"));
NumSetMaterials++;
}
Engine\Source\Runtime\Engine\Private\Materials\Material.cpp
case MP_Tangent:
Active = ShadingModels.HasAnyShadingModel({ MSM_DefaultLit, MSM_ClearCoat, MSM_KooEngine }) && (!bIsTranslucentBlendMode || !bIsVolumetricTranslucencyLightingMode);
break;
case MP_SubsurfaceColor:
Active = ShadingModels.HasAnyShadingModel({ MSM_Subsurface, MSM_PreintegratedSkin, MSM_TwoSidedFoliage, MSM_Cloth, MSM_KooEngine });
break;
case MP_CustomData0:
Active = ShadingModels.HasAnyShadingModel({ MSM_ClearCoat, MSM_Hair, MSM_Cloth, MSM_Eye, MSM_SubsurfaceProfile,MSM_KooEngine });
break;
case MP_CustomData1:
Active = ShadingModels.HasAnyShadingModel({ MSM_ClearCoat, MSM_Eye, MSM_KooEngine });
break;
Engine\Source\Runtime\Engine\Private\Materials\MaterialShader.cpp
/** 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_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;
case MSM_KooEngine: ShadingModelName = TEXT("MSM_KooEngine"); break;
default: ShadingModelName = TEXT("Unknown"); break;
}
return ShadingModelName;
}
Engine/Source/Runtime/Engine/Public/MaterialShared.h
inline bool IsSubsurfaceShadingModel(FMaterialShadingModelField ShadingModel)
{
return ShadingModel.HasShadingModel(MSM_Subsurface) || ShadingModel.HasShadingModel(MSM_PreintegratedSkin) ||
ShadingModel.HasShadingModel(MSM_SubsurfaceProfile) || ShadingModel.HasShadingModel(MSM_TwoSidedFoliage) ||
ShadingModel.HasShadingModel(MSM_Cloth) || ShadingModel.HasShadingModel(MSM_Eye) || ShadingModel.HasShadingModel(MSM_KooEngine);
}
Engine\Source\Runtime\Engine\Private\Materials\MaterialShared.cpp
case MP_SubsurfaceColor:
if (Material->MaterialDomain == MD_Volume)
{
return LOCTEXT("Extinction", "Extinction");
}
CustomPinNames.Add({MSM_Cloth, "Fuzz Color"});
CustomPinNames.Add({MSM_KooEngine, "Reflect Color"});
return FText::FromString(GetPinNameFromShadingModelField(Material->GetShadingModels(), CustomPinNames, "Subsurface Color"));
case MP_CustomData0:
CustomPinNames.Add({ MSM_ClearCoat, "Clear Coat" });
CustomPinNames.Add({MSM_Hair, "Backlit"});
CustomPinNames.Add({MSM_Cloth, "Cloth"});
CustomPinNames.Add({MSM_Eye, "Iris Mask"});
CustomPinNames.Add({MSM_SubsurfaceProfile, "Curvature" });
CustomPinNames.Add({MSM_KooEngine, "KE0"});
return FText::FromString(GetPinNameFromShadingModelField(Material->GetShadingModels(), CustomPinNames, "Custom Data 0"));
case MP_CustomData1:
CustomPinNames.Add({ MSM_ClearCoat, "Clear Coat Roughness" });
CustomPinNames.Add({MSM_Eye, "Iris Distance"});
CustomPinNames.Add({MSM_KooEngine, "KE1"});
return FText::FromString(GetPinNameFromShadingModelField(Material->GetShadingModels(), CustomPinNames, "Custom Data 1"));
Engine\Source\Runtime\Engine\Private\ShaderCompiler\ShaderGenerationUtil.cpp
void FShaderCompileUtilities::ApplyFetchEnvironment(FShaderMaterialPropertyDefines& SrcDefines, FShaderCompilerEnvironment& OutEnvironment)
{
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);
FETCH_COMPILE_BOOL(MATERIAL_SHADINGMODEL_KOOENGINE);
if (Mat.MATERIAL_SHADINGMODEL_EYE)
{
SetStandardGBufferSlots(Slots, bWriteEmissive, bHasTangent, bHasVelocity, bHasStaticLighting, bIsStrataMaterial);
Slots[GBS_CustomData] = bUseCustomData;
}
if (Mat.MATERIAL_SHADINGMODEL_KOOENGINE)
{
SetStandardGBufferSlots(Slots, bWriteEmissive, bHasTangent, bHasVelocity, bHasStaticLighting, bIsStrataMaterial);
Slots[GBS_CustomData] = bUseCustomData;
}
Engine\Source\Runtime\RenderCore\Private\ShaderMaterialDerivedHelpers.cpp
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_KOOENGINE));
Engine\Source\Runtime\RenderCore\Public\ShaderMaterial.h
uint8 MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT : 1;
uint8 MATERIAL_SHADINGMODEL_KOOENGINE : 1;