Files
UnrealEngineUWP/Engine/Shaders/Private/Strata/StrataTree.ush
Sebastien Hillaire 1bc3097d3b Strata - Added TransmittanceBelowAlongN which will be useful later with the path tracer when evaluating a single BSDF and choosing a refractions path.
#rb none
#preflight none
#fyi charles.derousiers, chris.kulla

[CL 20039247 by Sebastien Hillaire in ue5-main branch]
2022-05-04 05:35:51 -04:00

487 lines
22 KiB
Plaintext

#include "/Engine/Private/Strata/StrataEvaluation.ush"
#include "/Engine/Private/ShadingCommon.ush"
#ifndef STRATA_OPAQUE_MATERIAL
#define STRATA_OPAQUE_MATERIAL 0
#endif
// STRATA_TODO We assume layers all have the same IOR. But we should take into account the material later.
// For now, we suppose no IOR changes at interface until they are tracked properly
#define WATER_IOR 1.0f
#define AIR_IOR 1.0f
///////////////////////////////////////////////////////////////////////////////
// Utilities
void PostProcessSlabBeforeLighting(inout FStrataBSDF BSDF)
{
// Two sided lighting can only be evaluated on the bottom layer, together with option SSS. Otherwise, the simple volume will be used.
const bool bIsThin = BSDF.bIsBottom && BSDF_GETISTHIN(BSDF);
// We want simple volumetric only if the MFP input is pluged in, otherwise we avoid dealing with simple volumetric.
// We also do not want to use the simple volumetric path if we are dealing with an opaque material and this slab is not at the bottom.
// And when opaque, the bottom layer must be opaque and thus will ahve a solid opaque diffuse color.
const bool bIsSimpleVolume = !bIsThin && BSDF_GETHASMFP(BSDF) && (!STRATA_OPAQUE_MATERIAL || (STRATA_OPAQUE_MATERIAL && !BSDF.bIsBottom));
if (bIsSimpleVolume)
{
EnableSlabBSDFSimpleVolumetric(BSDF);
}
if (bIsThin)
{
EnableSlabBSDFIsThin(BSDF);
}
else
{
// If not selected or not possible to have two sided lighting enabled (not bottom layer or SSSProfile is enabled), let's make sure we disable the feature.
BSDF_SETISTHIN(BSDF, 0);
}
}
void PostProcessBSDFBeforeLighting(inout FStrataBSDF BSDF)
{
// Sanitize BSDF before it is used for forward shading
StrataSanitizeBSDF(BSDF);
switch (BSDF_GETTYPE(BSDF))
{
case STRATA_BSDF_TYPE_SLAB:
{
PostProcessSlabBeforeLighting(BSDF);
break;
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Tree processing functions
void UpdateSingleBSDFOperatorCoverageTransmittance(
FStrataPixelHeader StrataPixelHeader,
inout FStrataTree StrataTree,
inout FStrataBSDF CurrentBSDF,
FStrataIntegrationSettings Settings,
FStrataAddressing NullStrataAddressing,
float3 V
)
{
#if STRATA_INLINE_SHADING
#define Op StrataTree.Operators[CurrentBSDF.OperatorIndex]
// this feature is only needed for development/editor - we can compile it out for a shipping build (see r.CompileShadersForDevelopment cvar help)
#if USE_DEVELOPMENT_SHADERS
// We progressively remove top layers but never the bottom one.
CurrentBSDF.Coverage = Op.LayerDepth < Settings.PeelLayersAboveDepth && !CurrentBSDF.bIsBottom ? 0.0f : CurrentBSDF.Coverage;
#endif
const float Roughness = StrataGetBSDFRoughness(CurrentBSDF);
// Extract the true thickness of the BSDF before it is cast into the normalised Slab thickness we used.
// for opaque rough refraction, we are only interested in thickness of non bottom layers.
Op.OpaqueRoughRefractThicknessCm = CurrentBSDF.bIsBottom ? 0.0f : CurrentBSDF.ThicknessCm;
Op.OpaqueRoughRefractCoverage = CurrentBSDF.bIsTop ? CurrentBSDF.Coverage : 0.0f;
Op.OpaqueRoughRefractTopRoughness = CurrentBSDF.bIsTop ? Roughness : 0.0f;
PostProcessBSDFBeforeLighting(CurrentBSDF);
// Compute current BSDF transmittance
float3x3 TangentBasis = StrataGetBSDFSharedBasis_InlineShading(StrataPixelHeader, CurrentBSDF, NullStrataAddressing);
float3 LEqualN = TangentBasis[2];
FStrataBSDFContext StrataBSDFContext = StrataCreateBSDFContext(StrataPixelHeader, CurrentBSDF, NullStrataAddressing, V, LEqualN);
FStrataEvaluateResult BSDFEvaluate = StrataEvaluateBSDF(StrataBSDFContext, Settings);
float CurrentBSDFCoverage = CurrentBSDF.Coverage;
// We multiply this weight with coverage:
// - Because when coming from parameter blending, we need to scale the output down according to coverage resulting from parameter blending.
// - That will be applied on emissive and reflected light, so we do not need to apply that anywhere else.
// - When coming from non parameter blending, this is equal identity 1 and the operator parsing will continue to correctly weight the BSDF according to the tree.
CurrentBSDF.LuminanceWeightV = float3(1.0f, 1.0f, 1.0f) * CurrentBSDFCoverage;
CurrentBSDF.TransmittanceAboveAlongN = float3(1.0f, 1.0f, 1.0f); // Initialise to "no matter above"
// All BSDF are considered for contribution as the top BSDF can have their coverage dip to 0 and then another BSDF need to be considered for the top layer representation.
CurrentBSDF.TopLayerDataWeight = 1.0f;
Op.Coverage = CurrentBSDFCoverage;
Op.ThroughputAlongV = BSDFEvaluate.ThroughputV;
Op.TransmittanceAlongN = BSDFEvaluate.TransmittanceAlongN;
// Evaluate refraction lobes.
const FBxDFEnergyTerms EnergyTerms = ComputeGGXSpecEnergyTerms(Roughness, StrataBSDFContext.SatNoV, StrataGetBSDFSpecularColor(CurrentBSDF), StrataGetBSDFSpecularF90(CurrentBSDF));
{
const float TopDownInterfaceEta = CurrentBSDF.bIsTop ? AIR_IOR / WATER_IOR : 1.0f;
FStrataLobeStatistic RefractedLobe = StrataGetRefractedLobe(StrataGetDiracLobe(V), EnergyTerms.E, Roughness, TopDownInterfaceEta);
// Account for transmittance of the medium (but ignoring scattering for now)
RefractedLobe.E *= BSDFEvaluate.ThroughputV;
// Reduce according to coverage. It is a approximation to handle rough refraction reduction according to coverage when relying on a single lob.
RefractedLobe = StrataWeightLobe(RefractedLobe, CurrentBSDFCoverage);
Op.TopDownRefractionLobeStat = RefractedLobe;
}
// Same operation but for a bottom up lob
{
const float BottomUpInterfaceEta = CurrentBSDF.bIsTop ? WATER_IOR / AIR_IOR : 1.0f;
const float3 NormalDown = float3(0, 0, -1);
FStrataLobeStatistic RefractedLobe = StrataGetRefractedLobe(StrataGetDiracLobe(NormalDown), EnergyTerms.E, Roughness, BottomUpInterfaceEta);
// Account for transmittance of the medium (but ignoring scattering for now)
RefractedLobe.E *= BSDFEvaluate.ThroughputV;
// Reduce according to coverage. It is a approximation to handle rough refraction reduction according to coverage when relying on a single lob.
RefractedLobe = StrataWeightLobe(RefractedLobe, CurrentBSDFCoverage);
Op.BottomUpRefractionLobeStat = RefractedLobe;
}
Op.TopDownRefractionWorldNormal = TangentBasis[2];
#undef Op
#endif // STRATA_INLINE_SHADING
}
void UpdateSingleOperatorCoverageTransmittance(inout FStrataTree StrataTree, int OpIndex)
{
#if STRATA_INLINE_SHADING
#define Op StrataTree.Operators[OpIndex]
#define OpA StrataTree.Operators[StrataTree.Operators[OpIndex].LeftIndex]
#define OpB StrataTree.Operators[StrataTree.Operators[OpIndex].RightIndex]
// Propagate bIsTop:
// - horizontal, add, weight operations: Any of the operand bIsTop should be enough to determine this operator depth
// - vertical: takes the top layer depth information (operand A)
// => we always take the operand A information.
Op.LayerDepth = OpA.LayerDepth;
switch (Op.Type)
{
case STRATA_OPERATOR_WEIGHT:
{
const float Weight = saturate(Op.Weight);
Op.Coverage = Weight * OpA.Coverage;
Op.ThroughputAlongV = OpA.ThroughputAlongV;
Op.TransmittanceAlongN = OpA.TransmittanceAlongN;
Op.TopDownRefractionLobeStat = StrataWeightLobe(OpA.TopDownRefractionLobeStat, Weight);
Op.TopDownRefractionWorldNormal = OpA.TopDownRefractionWorldNormal * Weight;
Op.BottomUpRefractionLobeStat = StrataWeightLobe(OpA.BottomUpRefractionLobeStat, Weight);
// Coverage does not affect rough refraction data
Op.OpaqueRoughRefractThicknessCm = OpA.OpaqueRoughRefractThicknessCm;
Op.OpaqueRoughRefractCoverage = OpA.OpaqueRoughRefractCoverage * Weight;
Op.OpaqueRoughRefractTopRoughness = OpA.OpaqueRoughRefractTopRoughness;
break;
}
case STRATA_OPERATOR_VERTICAL:
{
const float3 TopThroughputAlongV = OpA.ThroughputAlongV;
const float3 TopTransmittanceAlongN = OpA.TransmittanceAlongN;
const float3 BotThroughputAlongV = OpB.ThroughputAlongV;
const float3 BotTransmittanceAlongN = OpB.TransmittanceAlongN;
const float TopCoverage = OpA.Coverage;
const float BotCoverage = OpB.Coverage;
#if 0
// This is coverage assuming correlation
const float LayerMaxCoverage = max(TopCoverage, BotCoverage);
const float LayerMaxCoverageInv = LayerMaxCoverage <= 0.0f ? 1.0f : 1.0f / LayerMaxCoverage;
// If a layer has a lower coverage than the other, we account for that when compuing the Transmittance.
const float TransmittanceOne = 1.0f;
const float3 TopTransmittanceAdjustedV = lerp(TransmittanceOne, TopThroughputAlongV, TopCoverage * LayerMaxCoverageInv);
const float3 TopTransmittanceAdjustedL = lerp(TransmittanceOne, TopTransmittanceAlongN, TopCoverage * LayerMaxCoverageInv);
const float3 BotTransmittanceAdjustedV = lerp(TransmittanceOne, BotThroughputAlongV, BotCoverage * LayerMaxCoverageInv);
const float3 BotTransmittanceAdjustedL = lerp(TransmittanceOne, BotTransmittanceAlongN, BotCoverage * LayerMaxCoverageInv);
// Now we update the material transmittance and coverage
Op.Coverage = LayerMaxCoverage;
Op.ThroughputAlongV = TopTransmittanceAdjustedV * BotTransmittanceAdjustedV;
Op.TransmittanceAlongN = TopTransmittanceAdjustedL * BotTransmittanceAdjustedL;
#else
FVerticalLayeringInfo Info = GetVerticalLayeringInfo(TopCoverage, BotCoverage);
Op.Coverage = Info.Coverage;
Op.ThroughputAlongV = Info.TransmittanceOnlyTop * TopThroughputAlongV + Info.TransmittanceOnlyBottom * BotThroughputAlongV + Info.TransmittanceTopAndBottom * TopThroughputAlongV * BotThroughputAlongV;
Op.TransmittanceAlongN = Info.TransmittanceOnlyTop * TopTransmittanceAlongN + Info.TransmittanceOnlyBottom * BotTransmittanceAlongN + Info.TransmittanceTopAndBottom * TopTransmittanceAlongN * BotTransmittanceAlongN;
#endif
Op.VerticalTop_Coverage = OpA.Coverage;
Op.VerticalTop_ThroughputAlongV = OpA.ThroughputAlongV;
Op.VerticalTop_TransmittanceAlongN = OpA.TransmittanceAlongN;
Op.VerticalBot_Coverage = OpB.Coverage;
Op.VerticalBot_ThroughputAlongV = OpB.ThroughputAlongV;
Op.VerticalBot_TransmittanceAlongN = OpB.TransmittanceAlongN;
// Project top lob through bottom layer assuming medium have same IOR.
{
const float TopDownInterfaceEta = 1.0f;
Op.TopDownRefractionLobeStat = StrataGetRefractedLobe(StrataOppositeLobe(OpA.TopDownRefractionLobeStat),
/*InterfaceFDG*/0.0f, StrataLobeVarianceToRoughness(OpB.TopDownRefractionLobeStat.Sigma), TopDownInterfaceEta);
Op.TopDownRefractionLobeStat.E *= saturate(OpB.ThroughputAlongV + (1.0f - OpB.Coverage)); // Combine with botton layer medium and specular transmittance
// The ratio of BottomSurfaceOnlyVisibile and visible through top layer (with a scale of 0.5 because at maximum both surfaces will be visible) as a fonction of the total coverage.
const float RefractionNormalMix = saturate((Info.SurfaceBottom + 0.5f * Info.TransmittanceTopAndBottom * dot(TopThroughputAlongV, 0.33.xxx)) / max(STRATA_EPSILON, Info.Coverage));
Op.TopDownRefractionWorldNormal = lerp(OpA.TopDownRefractionWorldNormal, OpB.TopDownRefractionWorldNormal, RefractionNormalMix);
}
// Project bottom lob through top layer.
{
const bool bIsTop = Op.LayerDepth == 0;
const float BottomUpInterfaceEta = bIsTop ? WATER_IOR / AIR_IOR : 1.0f;
Op.BottomUpRefractionLobeStat = StrataGetRefractedLobe(StrataOppositeLobe(OpB.BottomUpRefractionLobeStat),
/*InterfaceFDG*/0.0f, StrataLobeVarianceToRoughness(OpA.BottomUpRefractionLobeStat.Sigma), BottomUpInterfaceEta);
Op.BottomUpRefractionLobeStat.E *= saturate(OpA.ThroughputAlongV + (1.0f - OpA.Coverage)); // Combine with top layer medium and specular transmittance
}
// Vertical layering accumulates both operators thickness and only keep the top layer roughness and coverage, see OpaqueRoughRefractTopRoughness declaration for the details.
Op.OpaqueRoughRefractThicknessCm = OpA.OpaqueRoughRefractThicknessCm + OpB.OpaqueRoughRefractThicknessCm;
Op.OpaqueRoughRefractCoverage = OpA.OpaqueRoughRefractCoverage;
Op.OpaqueRoughRefractTopRoughness = OpA.OpaqueRoughRefractTopRoughness;
Op.VerticalTop_TopDownRefractionLobeStat = OpA.TopDownRefractionLobeStat;
Op.VerticalTop_BottomUpRefractionLobeStat = OpA.BottomUpRefractionLobeStat;
break;
}
case STRATA_OPERATOR_HORIZONTAL:
{
const float Mix = saturate(Op.Weight);
const float AMix = 1.0 - Mix;
const float BMix = Mix;
Op.Coverage = AMix * OpA.Coverage + BMix * OpB.Coverage;
Op.ThroughputAlongV = (AMix * OpA.Coverage * OpA.ThroughputAlongV + BMix * OpB.Coverage * OpB.ThroughputAlongV) / max(STRATA_EPSILON, AMix * OpA.Coverage + BMix * OpB.Coverage);
Op.TransmittanceAlongN = (AMix * OpA.Coverage * OpA.TransmittanceAlongN + BMix * OpB.Coverage * OpB.TransmittanceAlongN) / max(STRATA_EPSILON, AMix * OpA.Coverage + BMix * OpB.Coverage);
Op.TopDownRefractionLobeStat = StrataHorizontalMixLobes(OpA.TopDownRefractionLobeStat, OpB.TopDownRefractionLobeStat, BMix);
Op.TopDownRefractionWorldNormal = lerp(OpA.TopDownRefractionWorldNormal, OpB.TopDownRefractionWorldNormal, BMix);
Op.BottomUpRefractionLobeStat = StrataHorizontalMixLobes(OpA.BottomUpRefractionLobeStat, OpB.BottomUpRefractionLobeStat, BMix);
// Horizontal mixes both operators thickness
Op.OpaqueRoughRefractThicknessCm = lerp(OpA.OpaqueRoughRefractThicknessCm, OpB.OpaqueRoughRefractThicknessCm, BMix);
Op.OpaqueRoughRefractCoverage = lerp(OpA.OpaqueRoughRefractCoverage, OpB.OpaqueRoughRefractCoverage, BMix);
Op.OpaqueRoughRefractTopRoughness = lerp(OpA.OpaqueRoughRefractTopRoughness, OpB.OpaqueRoughRefractTopRoughness, BMix);
break;
}
case STRATA_OPERATOR_ADD:
{
const float SafeABSDFCoverage = saturate(OpA.Coverage);
const float SafeBBSDFCoverage = saturate(OpB.Coverage);
const float AMixFactor = SafeABSDFCoverage / max(STRATA_EPSILON, SafeABSDFCoverage + SafeBBSDFCoverage);
Op.Coverage = saturate(OpA.Coverage + OpB.Coverage);
Op.ThroughputAlongV = lerp(OpB.ThroughputAlongV, OpA.ThroughputAlongV, AMixFactor);
Op.TransmittanceAlongN = lerp(OpB.TransmittanceAlongN, OpA.TransmittanceAlongN, AMixFactor);
Op.TopDownRefractionLobeStat = StrataHorizontalMixLobes(OpA.TopDownRefractionLobeStat, OpB.TopDownRefractionLobeStat, 0.5f);
Op.TopDownRefractionWorldNormal = lerp(OpA.TopDownRefractionWorldNormal, OpB.TopDownRefractionWorldNormal, 0.5f);
Op.BottomUpRefractionLobeStat = StrataHorizontalMixLobes(OpA.BottomUpRefractionLobeStat, OpB.BottomUpRefractionLobeStat, 0.5f);
Op.OpaqueRoughRefractThicknessCm = lerp(OpA.OpaqueRoughRefractThicknessCm, OpB.OpaqueRoughRefractThicknessCm, 0.5f);
Op.OpaqueRoughRefractCoverage = lerp(OpA.OpaqueRoughRefractCoverage, OpB.OpaqueRoughRefractCoverage, 0.5f);
Op.OpaqueRoughRefractTopRoughness = lerp(OpA.OpaqueRoughRefractTopRoughness, OpB.OpaqueRoughRefractTopRoughness, 0.5f);
break;
}
case STRATA_OPERATOR_THINFILM:
{
// Thin-film does not affect these property
Op.Coverage = OpA.Coverage;
Op.ThroughputAlongV = OpA.ThroughputAlongV;
Op.TransmittanceAlongN = OpA.TransmittanceAlongN;
Op.TopDownRefractionLobeStat = OpA.TopDownRefractionLobeStat;
Op.TopDownRefractionWorldNormal = OpA.TopDownRefractionWorldNormal;
Op.BottomUpRefractionLobeStat = OpA.BottomUpRefractionLobeStat;
Op.OpaqueRoughRefractThicknessCm = OpA.OpaqueRoughRefractThicknessCm;
Op.OpaqueRoughRefractCoverage = OpA.OpaqueRoughRefractCoverage;
Op.OpaqueRoughRefractTopRoughness = OpA.OpaqueRoughRefractTopRoughness;
break;
}
}
#undef Op
#undef OpA
#undef OpB
#endif // STRATA_INLINE_SHADING
}
#define Op StrataTree.Operators[OpIndex]
// Post-update visit operators
void UpdateAllBSDFWithBottomUpOperatorVisit_Weight(
inout FStrataTree StrataTree,
inout FStrataBSDF CurrentBSDF,
int OpIndex,
int PreviousIsInputA)
{
#if STRATA_INLINE_SHADING
const float Weight = saturate(Op.Weight);
CurrentBSDF.LuminanceWeightV *= Weight;
CurrentBSDF.Coverage *= Weight;
CurrentBSDF.TopLayerDataWeight *= Weight;
#endif // STRATA_INLINE_SHADING
}
void UpdateAllBSDFWithBottomUpOperatorVisit_Horizontal(
inout FStrataTree StrataTree,
inout FStrataBSDF CurrentBSDF,
int OpIndex,
int PreviousIsInputA)
{
#if STRATA_INLINE_SHADING
const float Mix = saturate(Op.Weight);
const float AMix = 1.0 - Mix;
const float BMix = Mix;
const float Weight = PreviousIsInputA > 0 ? AMix : BMix;
CurrentBSDF.LuminanceWeightV *= Weight;
CurrentBSDF.Coverage *= Weight;
CurrentBSDF.TopLayerDataWeight *= Weight;
#endif // STRATA_INLINE_SHADING
}
void UpdateAllBSDFWithBottomUpOperatorVisit_Vertical(
inout FStrataTree StrataTree,
inout FStrataBSDF CurrentBSDF,
int OpIndex,
int PreviousIsInputA)
{
#if STRATA_INLINE_SHADING
// PreviousIsInputA > 0 means it is a BSDF affecting the top layer so we do not affect it by anything for this vertical layering.
// Otherise, the BSDF comes from the bottom part so we affect it weights from the gathered top layer coverage/transmittance
CurrentBSDF.LuminanceWeightV *= PreviousIsInputA > 0 ? 1.0f : saturate(1.0f - Op.VerticalTop_Coverage) + saturate(Op.VerticalTop_Coverage) * Op.VerticalTop_ThroughputAlongV;
CurrentBSDF.TransmittanceAboveAlongN*= PreviousIsInputA > 0 ? 1.0f : saturate(1.0f - Op.VerticalTop_Coverage) + saturate(Op.VerticalTop_Coverage) * Op.VerticalTop_TransmittanceAlongN;
CurrentBSDF.TransmittanceBelowAlongN*= PreviousIsInputA ==0 ? 1.0f : saturate(1.0f - Op.VerticalBot_Coverage) + saturate(Op.VerticalBot_Coverage) * Op.VerticalBot_TransmittanceAlongN;
// If the BSDF is from the bottom, we reduce its contribution according to the top layer coverage only.
CurrentBSDF.TopLayerDataWeight *= PreviousIsInputA ? 1.0 : saturate(1.0f - Op.VerticalTop_Coverage);
if (PreviousIsInputA <= 0) // Only apply to BSDF from the bottom layer
{
// We propagate the bottom layer lob up after the top layer top layer simulate the fact that light rays are potentially heavily scattered/refracted by the top layer.
// The outcome is that we affect the bottom layer roughness to aggregate that fact.
// STRATA_TODO: take into account thickness (far-field for now).
// Evaluate the reflected lobe, as an approximation we only evaluate along the normal.
const float3 DummyWi = float3(0, 0, 1);
const float DummyInterfaceDFG = 0.5f;
FStrataLobeStatistic ReflectedLobe = StrataGetReflectedLobe(StrataGetDiracLobe(DummyWi), DummyInterfaceDFG, StrataGetBSDFRoughness(CurrentBSDF));
// Evaluate the reflected lobe after refraction through the top layer of the vertical operator.
// => This tells how light should be integrated when traveling up thorugh that layer.
const float TopLayerSigma = Op.VerticalTop_BottomUpRefractionLobeStat.Sigma;
const bool bIsTop = Op.LayerDepth == 0;
const float BottomUpInterfaceEta = bIsTop ? WATER_IOR / AIR_IOR : 1.0f;
FStrataLobeStatistic RefractedLobe = StrataGetRefractedLobe(StrataOppositeLobe(ReflectedLobe), DummyInterfaceDFG, StrataLobeVarianceToRoughness(TopLayerSigma), BottomUpInterfaceEta);/////////////////
StrataSetBSDFRoughness(CurrentBSDF, StrataLobeVarianceToRoughness(RefractedLobe.Sigma));
}
#endif // STRATA_INLINE_SHADING
}
// Pre-update visit operators
void PreUpdateAllBSDFWithBottomUpOperatorVisit_Vertical(
FStrataPixelHeader StrataPixelHeader,
inout FStrataTree StrataTree,
inout FStrataBSDF CurrentBSDF,
FStrataAddressing NullStrataAddressing,
inout bool bCanReceiveThinFilm,
float3 V,
int OpIndex,
int PreviousIsInputA)
{
#if STRATA_INLINE_SHADING
// If the BSDF is coated with a vertical layer, it can no longer receive thin film-coating
if (PreviousIsInputA <= 0)
{
bCanReceiveThinFilm = false;
}
#endif // STRATA_INLINE_SHADING
}
void PreUpdateAllBSDFWithBottomUpOperatorVisit_ThinFilm(
FStrataPixelHeader StrataPixelHeader,
inout FStrataTree StrataTree,
inout FStrataBSDF CurrentBSDF,
FStrataAddressing NullStrataAddressing,
inout bool bCanReceiveThinFilm,
float3 V,
int OpIndex,
int PreviousIsInputA)
{
#if STRATA_INLINE_SHADING
if (bCanReceiveThinFilm && BSDF_GETTYPE(CurrentBSDF) == STRATA_BSDF_TYPE_SLAB)
{
const float3x3 TangentBasis = StrataGetBSDFSharedBasis_InlineShading(StrataPixelHeader, CurrentBSDF, NullStrataAddressing);
const float3 N = TangentBasis[2];
const float NoV = saturate(dot(N, V));
StrataGetThinFilmF0F90(NoV, Op.ThinFilmThickness, Op.ThinFilmIOR, SLAB_F0(CurrentBSDF), SLAB_F90(CurrentBSDF));
}
#endif // STRATA_INLINE_SHADING
}
#undef Op
///////////////////////////////////////////////////////////////////////////////
// Legacy materials conversion
void LegacyUpdateBSDFsOperators(inout FStrataPixelHeader StrataPixelHeader, inout FStrataTree StrataTree, FStrataIntegrationSettings Settings, FStrataAddressing NullStrataAddressing, float3 V)
{
// This must match what is done in StrataConvertLegacyMaterialDynamic
UpdateSingleBSDFOperatorCoverageTransmittance(StrataPixelHeader, StrataTree, StrataTree.BSDFs[0], Settings, NullStrataAddressing, V);
UpdateSingleBSDFOperatorCoverageTransmittance(StrataPixelHeader, StrataTree, StrataTree.BSDFs[1], Settings, NullStrataAddressing, V);
// MaxDistanceFromLeaves = 1
UpdateSingleOperatorCoverageTransmittance(StrataTree, /*OperatorIndex*/2);
UpdateSingleOperatorCoverageTransmittance(StrataTree, /*OperatorIndex*/3);
// MaxDistanceFromLeaves = 2
UpdateSingleOperatorCoverageTransmittance(StrataTree, /*OperatorIndex*/4);
#if STRATA_LEGACY_MATERIAL_APPLIES_FINAL_WEIGHT
// MaxDistanceFromLeaves = 3
UpdateSingleOperatorCoverageTransmittance(StrataTree, /*OperatorIndex*/5);
#endif
UpdateAllBSDFWithBottomUpOperatorVisit_Weight (StrataTree, StrataTree.BSDFs[0], /*OperatorIndex*/2, /*PreviousIsInputA*/1);
UpdateAllBSDFWithBottomUpOperatorVisit_Vertical (StrataTree, StrataTree.BSDFs[0], /*OperatorIndex*/4, /*PreviousIsInputA*/1);
#if STRATA_LEGACY_MATERIAL_APPLIES_FINAL_WEIGHT
UpdateAllBSDFWithBottomUpOperatorVisit_Weight (StrataTree, StrataTree.BSDFs[0], /*OperatorIndex*/5, /*PreviousIsInputA*/1);
#endif
UpdateAllBSDFWithBottomUpOperatorVisit_Weight (StrataTree, StrataTree.BSDFs[1], /*OperatorIndex*/3, /*PreviousIsInputA*/1);
UpdateAllBSDFWithBottomUpOperatorVisit_Vertical (StrataTree, StrataTree.BSDFs[1], /*OperatorIndex*/4, /*PreviousIsInputA*/0);
#if STRATA_LEGACY_MATERIAL_APPLIES_FINAL_WEIGHT
UpdateAllBSDFWithBottomUpOperatorVisit_Weight (StrataTree, StrataTree.BSDFs[1], /*OperatorIndex*/5, /*PreviousIsInputA*/1);
#endif
}