// 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; }