Files
UnrealEngineUWP/Engine/Shaders/Private/Strata/StrataLegacyConversion.ush
Charles deRousiers 2b010d77fb Add pre-integrated SSS material conversion.
#rb none
#jira none
#preflight shader
#fyi sebastien.hillaire

[CL 20449809 by Charles deRousiers in ue5-main branch]
2022-06-01 04:31:58 -04:00

688 lines
24 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "../Common.ush"
struct FStrataLegacyParameters
{
FStrataPixelFootprint PixelFootprint;
bool UseMetalness;
float3 DiffuseAlbedo;
float3 F0;
float3 F90;
float3 BaseColor;
float Specular;
float Metallic;
float Roughness;
float Anisotropy;
float SSSProfileID;
float3 SSSMFP;
float SSSMFPScale;
float SSSPhaseAniso;
bool UseSSSDiffusion;
float3 Emissive;
float FuzzAmount;
float3 FuzzColor;
float Thickness;
uint SharedLocalBasisIndex;
int LayerDepth;
int bIsBottom;
float Weight;
};
FStrataLegacyParameters InitStrataLegacyParameters(FStrataPixelFootprint InPixelFootprint, uint InSharedLocalBasisIndex, float InWeight)
{
const float3 Zeros = float3(0, 0, 0);
FStrataLegacyParameters Out;
Out.UseMetalness = true;
Out.DiffuseAlbedo = Zeros;
Out.F0 = Zeros;
Out.F90 = 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.UseSSSDiffusion = false;
Out.Emissive = Zeros;
Out.FuzzAmount = 0.f;
Out.FuzzColor = Zeros;
Out.Thickness = STRATA_LAYER_DEFAULT_THICKNESS_CM;
Out.SharedLocalBasisIndex = InSharedLocalBasisIndex;
Out.LayerDepth = 0;
Out.bIsBottom = 1;
Out.Weight = InWeight;
Out.PixelFootprint = InPixelFootprint;
return Out;
}
FStrataData CreateLegacySlab(
FStrataLegacyParameters In, inout uint SharedLocalBasisTypes,
inout FStrataTree StrataTree,
int OperatorIndex, int BSDFIndex)
{
const float3 Zeros = float3(0, 0, 0);
const float3 Ones = float3(1, 1, 1);
// Fixed layer structure for helping compiler to unroll and optimize shader
return PromoteParameterBlendedBSDFToOperator(
GetStrataSlabBSDF(
In.PixelFootprint,
In.UseMetalness, // UseMetalness
In.BaseColor, // BaseColor - Metalness workflow
Ones, // EdgeColor - Metalness workflow
In.Specular, // Specular - Metalness workflow
In.Metallic, // Metallic - Metalness workflow
In.DiffuseAlbedo, // DiffuseAlbedo - !Metalness workflow
In.F0, // F0 - !Metalness workflow
In.F90, // F90 - !Metalness workflow
In.Roughness, // Roughness
In.Anisotropy, // Anisotropy
In.SSSProfileID, // SSSProfileID
In.SSSMFP, // SSSMFP
In.SSSMFPScale, // SSSMFPScale
In.SSSPhaseAniso, // SSSPhaseAniso
In.UseSSSDiffusion, // UseSSSDiffusion
In.Emissive, // Emissive
0.f, // Haziness
In.FuzzAmount, // FuzzAmount
In.FuzzColor, // FuzzColor
In.Thickness,
In.SharedLocalBasisIndex, SharedLocalBasisTypes),
StrataTree,
OperatorIndex,
BSDFIndex,
In.LayerDepth,
In.bIsBottom);
}
// 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 Strata 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.
FStrataData StrataConvertLegacyMaterialDynamic(
FStrataPixelFootprint PixelFootprint,
float3 BaseColor, float Specular, float Metallic,
float Roughness, float Anisotropy,
float3 SubSurfaceColor, float SubSurfaceProfileId,
float ClearCoat, float ClearCoatRoughness,
float3 Emissive,
float Opacity,
float3 TransmittanceColor,
float3 WaterScatteringCoefficients, float3 WaterAbsorptionCoefficients, float WaterPhaseG, float3 ColorScaleBehindWater,
uint ShadingModel,
uint SharedLocalBasisIndex,
uint ClearCoatBottomNormal_SharedLocalBasisIndex,
inout uint SharedLocalBasisTypes,
inout FStrataTree StrataTree)
{
const float DefaultThickness = STRATA_LAYER_DEFAULT_THICKNESS_CM;
const float3 Zeros = float3(0, 0, 0);
const float3 Ones = float3(1, 1, 1);
// 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;
FStrataData Top_SLW = GetStrataSingleLayerWaterBSDF(
BaseColor, // BaseColor
Metallic, // Metallic
Specular, // Specular
Roughness, // Roughness
Emissive, // Emissive
Opacity, // TopMaterialOpacity
WaterAlbedo, // WaterAlbedo
WaterExtinction, // WaterExtinction
WaterPhaseG, // WaterPhaseG
ColorScaleBehindWater, // ColorScaleBehindWater
SharedLocalBasisIndex);
FStrataLegacyParameters Bot = InitStrataLegacyParameters(PixelFootprint, SharedLocalBasisIndex, 1.0f);
FStrataData Bot_Slab = CreateLegacySlab(Bot, SharedLocalBasisTypes, StrataTree, /*OperatorIndex*/1, /*BSDFIndex*/1);
FStrataData WTop_Slab = StrataWeight(Top_SLW , 1.0, StrataTree, /*OperatorIndex*/2, /*MaxDistanceFromLeaves*/1);
FStrataData WBot_Slab = StrataWeight(Bot_Slab, 0.0, StrataTree, /*OperatorIndex*/3, /*MaxDistanceFromLeaves*/1);
FStrataData Out = StrataVerticalLayering(WTop_Slab, WBot_Slab, StrataTree, /*OperatorIndex*/4, /*MaxDistanceFromLeaves*/2);
// Out maps to LegacyUpdateBSDFsOperators
return Out;
}
#endif
#if MATERIAL_SHADINGMODEL_HAIR
if (ShadingModel == SHADINGMODELID_HAIR)
{
return GetStrataHairBSDF(
BaseColor, // BaseColor
Metallic, // Scatter
Specular, // Specular
Roughness, // Roughness
ClearCoat, // Backlit
Emissive, // EmissiveColor
SharedLocalBasisIndex);
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
}
#endif
// Top/Bottom
FStrataLegacyParameters Top = InitStrataLegacyParameters(PixelFootprint, SharedLocalBasisIndex, 1.0f);
FStrataLegacyParameters Bot = InitStrataLegacyParameters(PixelFootprint, SharedLocalBasisIndex, 1.0f);
float FinalWeight = 1.0f;
if (ShadingModel == SHADINGMODELID_UNLIT)
{
// Unlit is handle with a emissive slab
Top.BaseColor = Zeros;
Top.Specular = 0.f;
Top.Metallic = 0.f;
Top.Roughness = 0.f;
Top.Anisotropy = Anisotropy;
Top.Emissive = Emissive;
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_DEFAULT_LIT)
{
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.Emissive = Emissive;
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_SUBSURFACE)
{
const float ThicknessInCm = STRATA_SIMPLEVOLUME_THICKNESS_CM;
const float3 MFPInCm = TransmittanceToMeanFreePath(SubSurfaceColor, ThicknessInCm * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.SSSMFP = max(1e-05f, MFPInCm); // Ensure the MFP is not null to force the material as have SSS
Top.SSSMFPScale = 1.0f;
Top.SSSPhaseAniso = 1.0f - Opacity; // Opaque-Thick: isotropic phase function, Thin: forward phase scattering function
Top.Emissive = Emissive;
Top.UseSSSDiffusion = false;
Top.Thickness = ThicknessInCm;
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
// STRATA_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 = saturate(1.f - Opacity);
Top.SSSMFP = 0;// MFPInCm;
Top.SSSMFPScale = 1.0f;
Top.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 SubSurfaceColro & BaseColor
Top.BaseColor = max(SubSurfaceColor, BaseColor);
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.SSSMFP = max(1e-05f, MFPInCm); // Ensure the MFP is not null to force the material as have SSS
Top.SSSMFPScale = 1.0f;
Top.SSSProfileID = 0.f;
Top.SSSMFPScale = 1.f - Opacity;
Top.SSSPhaseAniso = 0.93f;
Top.UseSSSDiffusion = true;
Top.Emissive = Emissive;
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_SUBSURFACE_PROFILE)
{
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.SSSProfileID = SubSurfaceProfileId;
Top.SSSMFPScale = Opacity;
Top.SSSPhaseAniso = 0.93f;
Top.UseSSSDiffusion = true;
Top.Emissive = Emissive;
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_CLEAR_COAT)
{
// === BOTTOM layer ===
Bot.BaseColor = BaseColor;
Bot.Specular = Specular;
Bot.Metallic = Metallic;
Bot.Roughness = Roughness;
Bot.Anisotropy = Anisotropy;
Bot.SSSProfileID = 0.f;
Bot.SSSMFP = Zeros;
Bot.SSSMFPScale = 0.f;
Bot.Emissive = Zeros;
Bot.SharedLocalBasisIndex = ClearCoatBottomNormal_SharedLocalBasisIndex;
Bot.LayerDepth = 1;
Bot.bIsBottom = 1;
Bot.Weight = 1.f;
// === TOP layer ===
// The top layer has a hard coded specular value of 0.5 (F0 = 0.04)
// BaseColor = 0 to only feature absorption, no scattering
// The original clear coat is a complex assemblage of arbitrary functions that do not always make sense.
// To simplify things, we set the top slab BSDF as having a constant Grey scale transmittance.
// As for the original, this is achieved with coverage so both transmittance and specular contribution vanishes
// Now setup the mean free path with a hard coded transmittance of 0.75 when viewing the surface perpendicularly
const float Thickness = DefaultThickness;
const float3 MFP = TransmittanceToMeanFreePath(0.75f, Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
Top.BaseColor = Zeros;
Top.Specular = 0.5f;
Top.Metallic = 0.f;
Top.Roughness = ClearCoatRoughness;
Top.Anisotropy = Anisotropy;
Top.SSSProfileID = 0.f;
Top.SSSMFP = MFP;
Top.SSSMFPScale = 1.f;
Top.Emissive = Emissive;
Top.Thickness = Thickness;
Top.SharedLocalBasisIndex = SharedLocalBasisIndex;
Top.LayerDepth = 0;
Top.bIsBottom = 0;
Top.Weight = ClearCoat;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
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 = STRATA_LAYER_ISTHIN_THICKNESS_THRESHOLD_CM - 1e-5f;
const float3 MFP = TransmittanceToMeanFreePath(SubSurfaceColor /*TransmittanceColor*/, Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.SSSProfileID = 0.f;
Top.SSSMFP = MFP;
Top.SSSMFPScale = 1.f;
Top.Emissive = Emissive;
Top.Thickness = Thickness;
// Take in account the legacy opacity weighting for translucent material
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_CLOTH)
{
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.SSSProfileID = 0.f;
Top.SSSMFP = 0.f;
Top.SSSMFPScale = 0.f;
Top.Emissive = Emissive;
Top.FuzzAmount = ClearCoat;
Top.FuzzColor = SubSurfaceColor;
Bot.Weight = 0.f;
FinalWeight = 1.0f;
#if STRATA_TRANSLUCENT_MATERIAL
FinalWeight = Opacity;
#endif
}
else if (ShadingModel == SHADINGMODELID_EYE)
{
const float IrisMask = ClearCoat;
const float IrisDistance = ClearCoatRoughness;
// Lerp transmittance rather MFP, as transmittance is perceptually linear unlike MFP
const float Thickness = DefaultThickness;
const float3 MFP = TransmittanceToMeanFreePath(IrisMask.xxx, Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
// Cornea/Sclera
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = 0.f;
Top.Roughness = Roughness;
Top.Anisotropy = 0.f;
Top.SSSProfileID = SubSurfaceProfileId;
Top.SSSMFP = MFP;
Top.SSSMFPScale = Opacity;
Top.Emissive = Emissive;
Top.SharedLocalBasisIndex = SharedLocalBasisIndex;
Top.LayerDepth = 0;
Top.bIsBottom = 0;
Top.Weight = 1.f;
// Iris
Bot.BaseColor = BaseColor;
Bot.Specular = Specular;
Bot.Metallic = .0f;
Bot.Roughness = Roughness;
Bot.Anisotropy = 0.f;
Bot.SSSProfileID = SubSurfaceProfileId;
Bot.SSSMFP = Zeros;
Bot.SSSMFPScale = Opacity;
Bot.Emissive = Emissive;
Bot.SharedLocalBasisIndex = ClearCoatBottomNormal_SharedLocalBasisIndex;
Bot.LayerDepth = 1;
Bot.bIsBottom = 1;
Bot.Weight = 1.f;
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
FinalWeight = 1.0f;
}
else if (ShadingModel == SHADINGMODELID_THIN_TRANSLUCENT)
{
const float Thickness = DefaultThickness;
// If the material is dieletric, bias the opacity so that the dieletric part extend further. This better matches the two layer approaches.
Opacity = lerp(1.f - Square(1.f - Opacity), Opacity, Metallic);
// Because we are using a single slab for simulating a 'coverage mix' between two BSDFs (a opaque metallic/conductor and a non-scattering translucent medium),
// we need to do some approximation. In order to reduce avoid hue shift due to difference between 'solid' base-color/diffuse-albedo and 'transparent' transmission
// color, we lerp BaseColor with transmittance color in LAB space so that the interpolated color minized its 'distance'
const float3 BaseColor_LAB = LinearRGB_2_LAB(BaseColor, XYZ_WHITE_REF_D65);
const float3 TransmittanceColor_LAB = LinearRGB_2_LAB(TransmittanceColor, XYZ_WHITE_REF_D65);
const float3 Color_LAB = lerp(TransmittanceColor_LAB, BaseColor_LAB, Opacity);
const float3 Color = LAB_2_LinearRGB(Color_LAB, XYZ_WHITE_REF_D65);
// Lerp the transmittance color rather than MFP as it is more perceptually linear
const float3 MFP = TransmittanceToMeanFreePath(lerp(Color, Zeros, Opacity), Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
const float F0Dieletrict = DielectricSpecularToF0(Specular);
const float3 TopF0 = lerp(F0Dieletrict, BaseColor, Metallic);
const float3 TopAlbedo = Color * (1.f - Metallic);
const float3 TopMFP = 0;
const float3 BotF0 = F0Dieletrict;
const float3 BotAlbedo = Zeros;
const float3 BotMFP = MFP;
Top.DiffuseAlbedo = lerp(BotAlbedo, TopAlbedo, Opacity);
Top.SSSMFP = lerp(BotMFP, TopMFP, Opacity);
Top.F0 = lerp(BotF0, TopF0, Opacity);
Top.F90 = Ones;
Top.UseMetalness = false;
Top.Roughness = Roughness;
Top.Anisotropy = 0.f;
Top.SSSProfileID = 0.f;
Top.SSSMFPScale = 1.f;
Top.Emissive = Emissive;
Top.Thickness = Thickness;
Top.SharedLocalBasisIndex = SharedLocalBasisIndex;
Top.Weight = 1.0f;
Bot.Weight = 0.0f;
// Reference two layers approach
#if 0
// Top slab BSDF as a simple Disney material
Top.BaseColor = BaseColor;
Top.Specular = Specular;
Top.Metallic = Metallic;
Top.Roughness = Roughness;
Top.Anisotropy = Anisotropy;
Top.SSSProfileID = 0.f;
Top.SSSMFP = Zeros;
Top.SSSMFPScale = 0.f;
Top.Emissive = Emissive;
Top.SharedLocalBasisIndex = SharedLocalBasisIndex;
// Bottom slab BSDF will be a simple absorption only layer
const float Thickness = DefaultThickness;
const float3 MFP = TransmittanceToMeanFreePath(TransmittanceColor, Thickness * CENTIMETER_TO_METER) * METER_TO_CENTIMETER;
// Assign specular properties shared with the top layer.
Bot.BaseColor = Zeros;
Bot.Specular = Specular;
Bot.Metallic = .0f;
Bot.Roughness = Roughness;
Bot.Anisotropy = 0.f;
Bot.SSSProfileID = .0f;
Bot.SSSMFP = MFP;
Bot.SSSMFPScale = 1.f;
Bot.Emissive = Zeros;
Bot.Thickness = Thickness;
Bot.SharedLocalBasisIndex = ClearCoatBottomNormal_SharedLocalBasisIndex;
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
// Now weight the top base material by opacity
Top.Weight = Opacity;
#endif
// Thin translucency model always have a coverage of 1. It also canont be used in a multiple shading model context.
FinalWeight = 1.0f;
}
// Fixed layer structure for helping compiler to unroll and optimize shader
// This must match what is done in PackStrataOut
FStrataData Top_Slab = CreateLegacySlab(Top, SharedLocalBasisTypes, StrataTree, /*OperatorIndex*/0, /*BSDFIndex*/0);
FStrataData Bot_Slab = CreateLegacySlab(Bot, SharedLocalBasisTypes, StrataTree, /*OperatorIndex*/1, /*BSDFIndex*/1);
FStrataData WTop_Slab= StrataWeight(Top_Slab, Top.Weight, StrataTree, /*OperatorIndex*/2, /*MaxDistanceFromLeaves*/1);
FStrataData WBot_Slab= StrataWeight(Bot_Slab, Bot.Weight, StrataTree, /*OperatorIndex*/3, /*MaxDistanceFromLeaves*/1);
FStrataData Out = StrataVerticalLayering(WTop_Slab, WBot_Slab, StrataTree, /*OperatorIndex*/4, /*MaxDistanceFromLeaves*/2);
// Take in account the legacy opacity weighting for translucent material
#if STRATA_LEGACY_MATERIAL_APPLIES_FINAL_WEIGHT
{
Out = StrataWeight(Out, FinalWeight, StrataTree, /*OperatorIndex*/5, /*MaxDistanceFromLeaves*/3);
}
#endif
#if STRATA_LEGACY_PREMULT_ALPHA_OVERRIDE
Out.PreMultipliedAlphaOverrideCoverage = Opacity;
#endif
// We also evaluate the inlined BSDF resulting from parameter blending in case it is used later.
// For instance, this is used for deferred decals. We only evaluate the top material as this is enough for decals.
FStrataData ParamBlendVertical = StrataWeightParameterBlending(Top_Slab, Top.Weight);
// if(Bot.Weight > 0.0)
// {
// const float DummyNoV = 1.0f;
// uint NewNormalIndex = BSDF_GETSHAREDLOCALBASISID(Top_Slab.InlinedBSDF);
// ParamBlendVertical = StrataVerticalLayeringParameterBlending(ParamBlendVertical, StrataWeightParameterBlending(Bot_Slab, Bot.Weight), NewNormalIndex, DummyNoV);
// }
#if STRATA_LEGACY_MATERIAL_APPLIES_FINAL_WEIGHT
Out.InlinedBSDF = StrataWeightParameterBlending(ParamBlendVertical, FinalWeight).InlinedBSDF;
#else
Out.InlinedBSDF = ParamBlendVertical.InlinedBSDF;
#endif
// Out maps to LegacyUpdateBSDFsOperators
return Out;
}
// 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
FStrataData StrataConvertLegacyMaterialStatic(
FStrataPixelFootprint PixelFootprint,
float3 BaseColor, float Specular, float Metallic,
float Roughness, float Anisotropy,
float3 SubSurfaceColor, float SubSurfaceProfileId,
float ClearCoat, float ClearCoatRoughness,
float3 Emissive,
float Opacity,
float3 TransmittanceColor,
float3 WaterScatteringCoefficients, float3 WaterAbsorptionCoefficients, float WaterPhaseG, float3 ColorScaleBehindWater,
uint ShadingModel,
uint SharedLocalBasisIndex,
uint ClearCoatBottomNormal_SharedLocalBasisIndex,
inout uint SharedLocalBasisTypes,
inout FStrataTree StrataTree)
{
FStrataData Out = GetInitialisedStrataData();
const float DefaultThickness = STRATA_LAYER_DEFAULT_THICKNESS_CM;
const float3 Zeros = float3(0, 0, 0);
const float3 Ones = float3(1, 1, 1);
if (ShadingModel == SHADINGMODELID_UNLIT)
{
const float GreyTransmittance = saturate(1.0f - Opacity);
#if MATERIALBLENDING_OPAQUE || MATERIALBLENDING_MASKED
// Opaque materials only write emissive.
Out = GetStrataUnlitBSDF(Emissive, 0.0f);
#elif MATERIALBLENDING_ALPHACOMPOSITE
// Uses (Luminance, black transmittance) for premultiplied alpha blending. Opacity is controled using coverage
Out = GetStrataUnlitBSDF(Emissive, 0.0f);
#if STRATA_INLINE_SHADING
Out.InlinedBSDF.Coverage = Opacity;
#endif
#elif MATERIALBLENDING_TRANSLUCENT
// Uses (Luminance, black transmittance) for translucency blending. Opacity is controled using coverage
Out = GetStrataUnlitBSDF(Emissive * Opacity, 0.0f);
#if STRATA_INLINE_SHADING
Out.InlinedBSDF.Coverage = Opacity;
#endif
#elif MATERIALBLENDING_ALPHAHOLDOUT
Out = GetStrataUnlitBSDF(0.0f, 1.0f);
#elif MATERIALBLENDING_ADDITIVE
// Emissive is weighted by opacity in the legacy material.
Out = GetStrataUnlitBSDF(Emissive * Opacity, 1.0f);
#elif MATERIALBLENDING_MODULATE
// Setting up emissive as the transmittance color. It is not clamped in case brightening is required.
Out = GetStrataUnlitBSDF(0.0f, Emissive);
#else
// Required default for some materials such as Editor UI
Out = GetStrataUnlitBSDF(Emissive, 0.0f);
#endif
}
else if (ShadingModel == SHADINGMODELID_HAIR)
{
Out = GetStrataHairBSDF(
BaseColor, // BaseColor
Metallic, // Scatter
Specular, // Specular
Roughness, // Roughness
ClearCoat, // Backlit
Emissive, // EmissiveColor
SharedLocalBasisIndex);
// No need to take into account opacity weighting for translucent material, as the coverage is assumed to be 1
}
else if (ShadingModel == SHADINGMODELID_SINGLELAYERWATER)
{
const float3 WaterExtinction = WaterScatteringCoefficients + WaterAbsorptionCoefficients;
const float3 WaterAlbedo = WaterScatteringCoefficients / WaterExtinction;
FStrataData Top_SLW = PromoteParameterBlendedBSDFToOperator(
GetStrataSingleLayerWaterBSDF(
BaseColor, // BaseColor
Metallic, // Metallic
Specular, // Specular
Roughness, // Roughness
Emissive, // Emissive
Opacity, // TopMaterialOpacity
WaterAlbedo, // WaterAlbedo
WaterExtinction, // WaterExtinction
WaterPhaseG, // WaterPhaseG
ColorScaleBehindWater, // ColorScaleBehindWater
SharedLocalBasisIndex),
StrataTree,
0 /*OperatorIndex*/,
0 /*BSDFIndex*/,
0 /*int LayerDepth*/,
1 /*int bIsBottom*/);
FStrataLegacyParameters Bot = InitStrataLegacyParameters(PixelFootprint, SharedLocalBasisIndex, 1.0f);
FStrataData Bot_Slab = CreateLegacySlab(Bot, SharedLocalBasisTypes, StrataTree, /*OperatorIndex*/1, /*BSDFIndex*/1);
FStrataData WTop_Slab = StrataWeight(Top_SLW, 1.0, StrataTree, /*OperatorIndex*/2, /*MaxDistanceFromLeaves*/1);
FStrataData WBot_Slab = StrataWeight(Bot_Slab, 0.0, StrataTree, /*OperatorIndex*/3, /*MaxDistanceFromLeaves*/1);
Out = StrataVerticalLayering(WTop_Slab, WBot_Slab, StrataTree, /*OperatorIndex*/4, /*MaxDistanceFromLeaves*/2);
// Out maps to LegacyUpdateBSDFsOperators
}
else
{
Out = StrataConvertLegacyMaterialDynamic(
PixelFootprint,
BaseColor, Specular, Metallic,
Roughness, Anisotropy,
SubSurfaceColor, SubSurfaceProfileId,
ClearCoat, ClearCoatRoughness,
Emissive,
Opacity,
TransmittanceColor,
WaterScatteringCoefficients, WaterAbsorptionCoefficients, WaterPhaseG, ColorScaleBehindWater,
ShadingModel,
SharedLocalBasisIndex,
ClearCoatBottomNormal_SharedLocalBasisIndex,
SharedLocalBasisTypes,
StrataTree);
}
return Out;
}