647 lines
24 KiB
HLSL
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;
|
|
}
|