Files
UnrealEngine/Engine/Shaders/Private/Substrate/SubstrateLegacyConversion.ush
2025-05-18 13:04:45 +08:00

647 lines
24 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "../Common.ush"
// Optimization: if opacity is 0 then revert to default shading model
// This is for matching legacy behavior. See ShadingModelsMaterial.ush.
#define SUBSURFACE_PROFILE_OPACITY_THRESHOLD 1
#define SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY (SUBSTRATE_TRANSLUCENT_MATERIAL || SUBSTRATE_MATERIAL_EXPORT_TYPE == SUBSTRATE_MATERIAL_EXPORT_OPACITY)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Helpers
void GetEyeNormals(
float IrisMask,
float IrisDistance,
in float3 InNormal,
in float3 InClearCoatNormal,
in float3 InCustomTangent,
inout float3 OutIrisNormal,
inout float3 OutIrisPlaneNormal);
///////////////////////////////////////////////////////////////////////////////////////////////////
struct FSubstrateLegacyParameters
{
FSubstratePixelFootprint PixelFootprint;
bool UseMetalness;
float3 DiffuseAlbedo;
float3 F0;
float3 F90;
float3 RawNormal;
float3 BaseColor;
float Specular;
float Metallic;
float Roughness;
float Anisotropy;
float SSSProfileID;
float3 SSSMFP;
float SSSMFPScale;
float SSSPhaseAniso;
uint SSSType;
float3 Emissive;
float SecondRoughness;
float SecondRoughnessWeight;
bool SecondRoughnessAsSimpleClearCoat;
bool ClearCoatUseBottomNormal;
float3 ClearCoatBottomNormal;
float FuzzAmount;
float3 FuzzColor;
float Thickness;
bool bIsThinSurface;
uint SharedLocalBasisIndex;
float Weight;
};
FSubstrateLegacyParameters InitSubstrateLegacyParameters(FSubstratePixelFootprint InPixelFootprint, uint InSharedLocalBasisIndex, float InWeight)
{
const float3 Zeros = float3(0, 0, 0);
FSubstrateLegacyParameters Out;
Out.UseMetalness = true;
Out.DiffuseAlbedo = Zeros;
Out.F0 = Zeros;
Out.F90 = Zeros;
Out.RawNormal = Zeros;
Out.BaseColor = Zeros;
Out.Specular = 0.5f;
Out.Metallic = 0.f;
Out.Roughness = 0.5f;
Out.Anisotropy = 0.f;
Out.SSSProfileID = 0.f;
Out.SSSMFP = Zeros;
Out.SSSMFPScale = 1.f;
Out.SSSPhaseAniso = 0.f;
Out.SSSType = SSS_TYPE_NONE;
Out.Emissive = Zeros;
Out.SecondRoughness = 0.0f;
Out.SecondRoughnessWeight = 0.0f;
Out.SecondRoughnessAsSimpleClearCoat = false;
Out.FuzzAmount = 0.f;
Out.FuzzColor = Zeros;
Out.Thickness = SUBSTRATE_LAYER_DEFAULT_THICKNESS_CM;
Out.bIsThinSurface = false;
Out.SharedLocalBasisIndex = InSharedLocalBasisIndex;
Out.Weight = InWeight;
Out.PixelFootprint = InPixelFootprint;
return Out;
}
FSubstrateData CreateLegacySlab(
FSubstrateLegacyParameters In, inout uint SharedLocalBasisTypes)
{
const float3 Zeros = float3(0, 0, 0);
const float3 Ones = float3(1, 1, 1);
float3 DiffuseAlbedo = In.DiffuseAlbedo;
float3 F0 = In.F0;
float3 F90 = In.F90;
if (In.UseMetalness > 0.0f)
{
DiffuseAlbedo = ComputeDiffuseAlbedo(In.BaseColor, In.Metallic);
F0 = ComputeF0(In.Specular, In.BaseColor, In.Metallic);
F90 = Ones;
}
// Fixed layer structure for helping compiler to unroll and optimize shader
return GetSubstrateSlabBSDF(
In.PixelFootprint,
In.RawNormal, // Normal
DiffuseAlbedo, // DiffuseAlbedo
F0, // F0
F90, // F90
In.Roughness, // Roughness
In.Anisotropy, // Anisotropy
In.SSSProfileID, // SSSProfileID
In.SSSMFP, // SSSMFP
In.SSSMFPScale, // SSSMFPScale
In.SSSPhaseAniso, // SSSPhaseAniso
In.SSSType, // SSSType
In.Emissive, // Emissive
In.SecondRoughness, // SecondRoughness
In.SecondRoughnessWeight, // SecondRoughnessWeight
In.SecondRoughnessAsSimpleClearCoat ? 1.0f : 0.0f, // SecondRoughnessAsSimpleClearCoat
In.ClearCoatUseBottomNormal ? 1.0f : 0.0f, // ClearCoatUseSecondNormal;
In.ClearCoatBottomNormal, // ClearCoatBottomNormal;
In.FuzzAmount, // FuzzAmount
In.FuzzColor, // FuzzColor
In.Roughness, // FuzzRoughness
1.0f, (GLINT_UV_TYPE)0, // GlintData
0.0f, // Specular profile
In.Thickness,
In.bIsThinSurface,
true, // bIsAtTheBottomOfTopology, legacy always has a single BSDF being at the bottom and top at teh same time.
In.SharedLocalBasisIndex, SharedLocalBasisTypes);
}
// Convert legacy shading models - Dynamic
// This function can handle dynamic shading models (i.e., known only at runtime).
// For this, the layer topology is 'fixed' and composed of two slabs vertically layered. This is done for
// helping the compiler to unroll Substrate BSDF traversing and packing. In most cases, the bottom slab is
// weighted by 0 and it will be removed once the data are written-out/packed.
FSubstrateData SubstrateConvertLegacyMaterialDynamic(
FSubstratePixelFootprint PixelFootprint,
float3 BaseColor, float Specular, float Metallic,
float Roughness, float Anisotropy,
float3 SubSurfaceColor, float SubSurfaceProfileId,
float ClearCoat, float ClearCoatRoughness,
float3 Emissive,
float Opacity,
float3 ThinTranslucentTransmittanceColor,
float ThinTranslucentSurfaceCoverage,
float3 WaterScatteringCoefficients, float3 WaterAbsorptionCoefficients, float WaterPhaseG, float3 ColorScaleBehindWater,
uint ShadingModel,
float3 RawNormal,
float3 RawTangent,
float3 RawClearCoatNormal,
float3 RawCustomTangent,
uint SharedLocalBasisIndex,
uint ClearCoatBottomNormal_SharedLocalBasisIndex,
inout uint SharedLocalBasisTypes)
{
const float DefaultThickness = SUBSTRATE_LAYER_DEFAULT_THICKNESS_CM;
const float3 Zeros = float3(0, 0, 0);
const float3 Ones = float3(1, 1, 1);
const float OneMinusOpacity = 1.f - Opacity;
// Can only mix Unlit / DefaultLit / Sub-Surface / Preintegrated-Skin / Subsurface-Profile / ClearCoat / Foliage / Cloth / Eye / Thin
// Note: If hair or single layer water are enabled with other shading model, the code generation won't be ideal, as the compiler will struggle with unrolling the BSDFs
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
if (ShadingModel == SHADINGMODELID_SINGLELAYERWATER)
{
const float3 WaterExtinction = WaterScatteringCoefficients + WaterAbsorptionCoefficients;
const float3 WaterAlbedo = WaterScatteringCoefficients / WaterExtinction;
return GetSubstrateSingleLayerWaterBSDF(
BaseColor, // BaseColor
Metallic, // Metallic
Specular, // Specular
Roughness, // Roughness
Emissive, // Emissive
Opacity, // TopMaterialOpacity
WaterAlbedo, // WaterAlbedo
WaterExtinction, // WaterExtinction
WaterPhaseG, // WaterPhaseG
ColorScaleBehindWater, // ColorScaleBehindWater
SharedLocalBasisIndex);
}
#endif // MATERIAL_SHADINGMODEL_SINGLELAYERWATER
#if MATERIAL_SHADINGMODEL_HAIR
if (ShadingModel == SHADINGMODELID_HAIR)
{
return GetSubstrateHairBSDF(
BaseColor, // BaseColor
Metallic, // Scatter
Specular, // Specular
Roughness, // Roughness
ClearCoat, // Backlit
Emissive, // EmissiveColor
SharedLocalBasisIndex);
}
#endif // MATERIAL_SHADINGMODEL_HAIR
#if MATERIAL_SHADINGMODEL_EYE
if (ShadingModel == SHADINGMODELID_EYE)
{
const float IrisMask = ClearCoat;
const float IrisDistance = ClearCoatRoughness;
float3 IrisNormal = RawNormal;
float3 IrisPlaneNormal = RawNormal;
GetEyeNormals(IrisMask, IrisDistance, RawNormal, RawClearCoatNormal, RawCustomTangent, IrisNormal, IrisPlaneNormal);
return GetSubstrateEyeBSDF(
BaseColor, // DiffuseAlbedo
Roughness, // Roughness
IrisMask, // IrisMask
IrisDistance, // IrisDistance
IrisNormal, // IrisNormal
IrisPlaneNormal, // IrisPlaneNormal
SubSurfaceProfileId, // SSS profile
Emissive, // EmissiveColor
SharedLocalBasisIndex);
}
#endif // MATERIAL_SHADINGMODEL_EYE
FSubstrateLegacyParameters LegacySlab = InitSubstrateLegacyParameters(PixelFootprint, SharedLocalBasisIndex, 1.0f);
LegacySlab.RawNormal = RawNormal;
float FinalWeight = 1.0f;
if (ShadingModel == SHADINGMODELID_UNLIT)
{
// Unlit is handle with a emissive slab
LegacySlab.BaseColor = Zeros;
LegacySlab.Specular = 0.f;
LegacySlab.Metallic = 0.f;
LegacySlab.Roughness = 0.f;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.Emissive = Emissive;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_DEFAULT_LIT)
{
LegacySlab.BaseColor = BaseColor;
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.Emissive = Emissive;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_SUBSURFACE)
{
const float ThicknessInCm = SUBSTRATE_SIMPLEVOLUME_THICKNESS_CM;
const float3 MFPInCm = TransmittanceToMeanFreePath(SubSurfaceColor, ThicknessInCm * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
LegacySlab.BaseColor = BaseColor;
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.SSSMFP = max(1e-05f, MFPInCm); // Ensure the MFP is not null to force the material as have SSS
LegacySlab.SSSMFPScale = 1.0f;
LegacySlab.SSSPhaseAniso = OneMinusOpacity; // Opaque-Thick: isotropic phase function, Thin: forward phase scattering function
LegacySlab.Emissive = Emissive;
LegacySlab.SSSType = SSS_TYPE_WRAP;
LegacySlab.Thickness = ThicknessInCm;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
// SUBSTRATE_TODO
// If we try to reduce the diffusion according to transmittance that will increase mfp and make the material disapear (make it optically thin).
// Instead for now we use a mfp of 0 and make the material vanish according to opacity.
// All this will be fixed when this material will be converted to LUT.
const float Transmittance = OneMinusOpacity;
LegacySlab.SSSMFP = 0;// MFPInCm;
LegacySlab.SSSMFPScale = 1.0f;
LegacySlab.Thickness = ThicknessInCm;
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_PREINTEGRATED_SKIN)
{
// Use default profile MFP (e.g., human skin) as MFP value for converting hardcoded pre-integrated SSS texture for deferred material.
const float3 MFPInCm = float3(1.0f, 0.088964f, 0.072095f) * 2.6748f * 0.1f;
// Legacy material uses Subsurface color as transmission 'tinting', but we can represent that with a single layer. So instead we take
// the max color of SubSurfaceColor & BaseColor
LegacySlab.BaseColor = max(SubSurfaceColor, BaseColor);
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.SSSMFP = max(1e-05f, MFPInCm); // Ensure the MFP is not null to force the material as have SSS
LegacySlab.SSSProfileID = 0.f;
LegacySlab.SSSMFPScale = OneMinusOpacity;
LegacySlab.SSSPhaseAniso = 0.93f;
LegacySlab.SSSType = SSS_TYPE_DIFFUSION;
LegacySlab.Emissive = Emissive;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_SUBSURFACE_PROFILE)
{
LegacySlab.BaseColor = BaseColor;
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
#if SUBSURFACE_PROFILE_OPACITY_THRESHOLD
if (Opacity > SSSS_OPACITY_THRESHOLD_EPS)
#endif
{
LegacySlab.SSSProfileID = SubSurfaceProfileId;
LegacySlab.SSSMFPScale = Opacity;
}
LegacySlab.SSSPhaseAniso = 0.93f;
LegacySlab.SSSType = SSS_TYPE_DIFFUSION; // SSS_TYPE_DIFFUSION_PROFILE will be selected in InternalGetSubstrateSlabBSDF based on SSSProfileID and SSSMFPScale.
LegacySlab.Emissive = Emissive;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_CLEAR_COAT)
{
const bool bUseBottomNormal = CLEAR_COAT_BOTTOM_NORMAL && any(RawClearCoatNormal != RawNormal);
LegacySlab.BaseColor = BaseColor;
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.SSSProfileID = 0.f;
LegacySlab.SSSMFP = Zeros;
LegacySlab.SSSMFPScale = 0.f;
LegacySlab.SecondRoughnessWeight = ClearCoat;
LegacySlab.SecondRoughness = ClearCoatRoughness;
LegacySlab.SecondRoughnessAsSimpleClearCoat = ClearCoat > 0.0f || bUseBottomNormal; // Haziness as simple clear coat layer, We need to maintain it if bottom normal are used to avoid any visual pop
LegacySlab.ClearCoatUseBottomNormal = bUseBottomNormal;
LegacySlab.ClearCoatBottomNormal = RawClearCoatNormal;
LegacySlab.Emissive = Emissive;
LegacySlab.Weight = 1.f;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_TWOSIDED_FOLIAGE)
{
// Set a thickness that will enabled the thin lighting model (corresponding to the legacy two-sided lighting model)
const float Thickness = SUBSTRATE_LAYER_DEFAULT_THICKNESS_CM;
const float3 MFPInCm = TransmittanceToMeanFreePath(SubSurfaceColor /*TransmittanceColor*/, Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
LegacySlab.BaseColor = BaseColor;
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.SSSProfileID = 0.f;
LegacySlab.SSSMFP = max(1e-05f, MFPInCm); // Ensure the MFP is not null to force the material as have SSS
LegacySlab.SSSMFPScale = 1.0f;
LegacySlab.SSSPhaseAniso = OneMinusOpacity; // Opaque-Thick: isotropic phase function, Thin: forward phase scattering function
LegacySlab.Emissive = Emissive;
LegacySlab.SSSType = SSS_TYPE_TWO_SIDED_WRAP;
LegacySlab.Thickness = Thickness;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_CLOTH)
{
LegacySlab.BaseColor = BaseColor;
LegacySlab.Specular = Specular;
LegacySlab.Metallic = Metallic;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = Anisotropy;
LegacySlab.SSSProfileID = 0.f;
LegacySlab.SSSMFP = 0.f;
LegacySlab.SSSMFPScale = 0.f;
LegacySlab.Emissive = Emissive;
LegacySlab.FuzzAmount = ClearCoat;
LegacySlab.FuzzColor = SubSurfaceColor;
FinalWeight = 1.0f;
#if SUBSTRATE_LEGACYCONVERT_OUTPUT_OPACITY
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_THIN_TRANSLUCENT)
{
const float Thickness = DefaultThickness;
const float3 TransColor = lerp(ThinTranslucentTransmittanceColor, Zeros, Opacity);
const float3 MFP = TransmittanceToMeanFreePath(TransColor, Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
const float F0Dieletrict = DielectricSpecularToF0(Specular);
const float3 TopF0 = lerp(F0Dieletrict, BaseColor, Metallic);
const float3 TopAlbedo = BaseColor * (1.f - Metallic);
const float3 BotF0 = F0Dieletrict;
const float3 BotAlbedo = Zeros;
LegacySlab.DiffuseAlbedo = lerp(BotAlbedo, TopAlbedo, Opacity);
LegacySlab.SSSMFP = MFP;
LegacySlab.F0 = lerp(BotF0, TopF0, Opacity);
LegacySlab.F90 = Ones;
LegacySlab.UseMetalness = false;
LegacySlab.Roughness = Roughness;
LegacySlab.Anisotropy = 0.f;
LegacySlab.SSSProfileID = 0.f;
LegacySlab.SSSMFPScale = 1.f;
LegacySlab.Emissive = Emissive;
LegacySlab.Thickness = Thickness;
LegacySlab.SharedLocalBasisIndex = SharedLocalBasisIndex;
LegacySlab.SSSType = SSS_TYPE_SIMPLEVOLUME; // This translucent explicitely use this mode to get colored translucency from SSSMFP.
// Opacity on the root node is the coverage of the disney model on top of the translucent part.
// Thin translucency model have a special surface coverage input.
FinalWeight = ThinTranslucentSurfaceCoverage;
}
// Fixed layer structure for helping compiler to unroll and optimize shader
FSubstrateData Slab = CreateLegacySlab(LegacySlab, SharedLocalBasisTypes);
#if SUBSTRATE_INLINE_SHADING
Slab.InlinedBSDF.Coverage = LegacySlab.Weight * FinalWeight; //////////////////// Remove FinalWeight? Do that in CreateLegacySlab?
#endif
return Slab;
}
// Convert legacy shading models - Static
// This function is for static single shading model (i.e., known at shader compilation time).
// It reuses the dynamic version for most part, but for special node like Unlit/Hair/Water,
// we use the dedicated node
FSubstrateData SubstrateConvertLegacyMaterialStatic(
FSubstratePixelFootprint PixelFootprint,
float3 BaseColor, float Specular, float Metallic,
float Roughness, float Anisotropy,
float3 SubSurfaceColor, float SubSurfaceProfileId,
float ClearCoat, float ClearCoatRoughness,
float3 Emissive,
float Opacity,
float3 ThinTranslucentTransmittanceColor,
float ThinTranslucentSurfaceCoverage,
float3 WaterScatteringCoefficients, float3 WaterAbsorptionCoefficients, float WaterPhaseG, float3 ColorScaleBehindWater,
uint ShadingModel,
float3 RawNormal,
float3 RawTangent,
float3 RawClearCoatNormal,
float3 RawCustomTangent,
uint SharedLocalBasisIndex,
uint ClearCoatBottomNormal_SharedLocalBasisIndex,
inout uint SharedLocalBasisTypes)
{
FSubstrateData Out = GetInitialisedSubstrateData();
const float DefaultThickness = SUBSTRATE_LAYER_DEFAULT_THICKNESS_CM;
const float3 Zeros = float3(0, 0, 0);
const float3 Ones = float3(1, 1, 1);
// We need to make sure a few values are safe for the transformations into slab input we do.
Metallic = saturate(Metallic);
ThinTranslucentTransmittanceColor = saturate(ThinTranslucentTransmittanceColor);
ThinTranslucentSurfaceCoverage = saturate(ThinTranslucentSurfaceCoverage);
Opacity = saturate(Opacity);
#if SUBSTRATE_USE_PREMULTALPHA_OVERRIDE
// Opacity is applied using the "Opacity Override" pin on the root node when using alpha composite (pre multiplied alpha).
// This is needed because some material might have the pin plugged in and the blending mode overriden on the material instance.
Opacity = 1.0f;
#endif
if (ShadingModel == SHADINGMODELID_UNLIT)
{
// Now we convert the legacy behavior to Substrate Coverage/Transmittance controls.
// Note: Emissive will always be weighted later by the Unlit BSDF Coverage (see SubstrateUpdateTreeUnlit).
const float GreyTransmittance = saturate(1.0f - Opacity);
#if MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED
// Opaque materials only write emissive.
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#elif MATERIALBLENDING_ALPHACOMPOSITE
// Uses (Luminance, black transmittance) for premultiplied alpha blending.
// Coverage over the background is specified through the root node input "Coverage Override".
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#elif MATERIALBLENDING_ALPHAHOLDOUT
// The MATERIALBLENDING_ALPHAHOLDOUT case needs to be before the MATERIALBLENDING_TRANSLUCENT case, as alphaholdout material have both cases defined.
Out = GetSubstrateUnlitBSDF(0.0f, GreyTransmittance, RawNormal);
#elif MATERIALBLENDING_TRANSLUCENT
// Uses (Luminance, black transmittance) for translucency blending. Opacity is controled using coverage.
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#if SUBSTRATE_INLINE_SHADING
Out.InlinedBSDF.Coverage = Opacity; // Applied to emissive via the Substrate Tree, (see SubstrateUpdateTreeUnlit).
#endif
#elif MATERIALBLENDING_ADDITIVE
// Emissive is weighted by opacity in the legacy material.
Out = GetSubstrateUnlitBSDF(Emissive * Opacity, 1.0f, RawNormal);
#elif MATERIALBLENDING_MODULATE
// Setting up emissive as the transmittance color. It is not clamped in case brightening is required.
Out = GetSubstrateUnlitBSDF(0.0f, Emissive, RawNormal);
#else
// Required default for some materials such as Editor UI.
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#endif
}
else if (ShadingModel == SHADINGMODELID_HAIR)
{
Out = GetSubstrateHairBSDF(
BaseColor, // BaseColor
Metallic, // Scatter
Specular, // Specular
Roughness, // Roughness
ClearCoat, // Backlit
Emissive, // EmissiveColor
SharedLocalBasisIndex);
}
else if (ShadingModel == SHADINGMODELID_EYE)
{
const float IrisMask = ClearCoat;
const float IrisDistance = ClearCoatRoughness;
float3 IrisNormal = RawNormal;
float3 IrisPlaneNormal = RawNormal;
GetEyeNormals(IrisMask, IrisDistance, RawNormal, RawClearCoatNormal, RawCustomTangent, IrisNormal, IrisPlaneNormal);
Out = GetSubstrateEyeBSDF(
BaseColor, // DiffuseAlbedo
Roughness, // Roughness
IrisMask, // IrisMask
IrisDistance, // IrisDistance
IrisNormal, // IrisNormal
IrisPlaneNormal, // IrisPlaneNormal
SubSurfaceProfileId, // SSS profile
Emissive, // EmissiveColor
SharedLocalBasisIndex);
}
else if (ShadingModel == SHADINGMODELID_SINGLELAYERWATER)
{
const float3 WaterExtinction= WaterScatteringCoefficients + WaterAbsorptionCoefficients;
const float3 WaterAlbedo = WaterScatteringCoefficients / WaterExtinction;
Out = GetSubstrateSingleLayerWaterBSDF(
BaseColor, // BaseColor
Metallic, // Metallic
Specular, // Specular
Roughness, // Roughness
Emissive, // Emissive
Opacity, // TopMaterialOpacity
WaterAlbedo, // WaterAlbedo
WaterExtinction, // WaterExtinction
WaterPhaseG, // WaterPhaseG
ColorScaleBehindWater, // ColorScaleBehindWater
SharedLocalBasisIndex);
}
else
{
Out = SubstrateConvertLegacyMaterialDynamic(
PixelFootprint,
BaseColor, Specular, Metallic,
Roughness, Anisotropy,
SubSurfaceColor, SubSurfaceProfileId,
ClearCoat, ClearCoatRoughness,
Emissive,
Opacity,
ThinTranslucentTransmittanceColor,
ThinTranslucentSurfaceCoverage,
WaterScatteringCoefficients, WaterAbsorptionCoefficients, WaterPhaseG, ColorScaleBehindWater,
ShadingModel,
RawNormal,
RawTangent,
RawClearCoatNormal,
RawCustomTangent,
SharedLocalBasisIndex,
ClearCoatBottomNormal_SharedLocalBasisIndex,
SharedLocalBasisTypes);
}
return Out;
}
FSubstrateData SubstrateCreateUIMaterial(
float3 Emissive,
float Opacity)
{
// We create a UI material using a Unlit Substrate BSDF. And we adapt to the blending mode in order to respect legacy behavior.
FSubstrateData Out = GetInitialisedSubstrateData();
const float3 RawNormal = float3(0, 0, 1); // Unused in this case.
Opacity = saturate(Opacity);
const float GreyTransmittance = 1.0f - Opacity;
#if MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED
// Opaque materials only write emissive.
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#elif MATERIALBLENDING_ALPHACOMPOSITE
// Uses (Luminance, black transmittance) for premultiplied alpha blending.
// Coverage over the background is specified through the root node input "Coverage Override".
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#elif MATERIALBLENDING_ALPHAHOLDOUT
// The MATERIALBLENDING_ALPHAHOLDOUT case needs to be before the MATERIALBLENDING_TRANSLUCENT case, as alphaholdout material have both cases defined.
Out = GetSubstrateUnlitBSDF(0.0f, GreyTransmittance, RawNormal);
#elif MATERIALBLENDING_TRANSLUCENT
// Uses (Luminance, black transmittance) for translucency blending. Opacity is controled using coverage.
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#if SUBSTRATE_INLINE_SHADING
Out.InlinedBSDF.Coverage = Opacity; // Applied to emissive via the Substrate Tree, (see SubstrateUpdateTreeUnlit).
#endif
#elif MATERIALBLENDING_ADDITIVE
// Emissive is weighted by opacity in the legacy material.
Out = GetSubstrateUnlitBSDF(Emissive * Opacity, 1.0f, RawNormal);
#elif MATERIALBLENDING_MODULATE
// Setting up emissive as the transmittance color. It is not clamped in case brightening is required.
Out = GetSubstrateUnlitBSDF(0.0f, Emissive, RawNormal);
#else
// Required default for some materials such as Editor UI.
Out = GetSubstrateUnlitBSDF(Emissive, 0.0f, RawNormal);
#endif
return Out;
}