// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= LumenFrontLayerTranslucency.usf =============================================================================*/ #include "../Common.ush" #include "../BRDF.ush" // Material pass reroutes #define SceneTexturesStruct LumenFrontLayerTranslucencyGBufferPass.SceneTextures #include "/Engine/Generated/Material.ush" #include "/Engine/Generated/VertexFactory.ush" struct FLumenFrontLayerTranslucencyGBufferInterpolantsVSToPS { }; struct FLumenFrontLayerTranslucencyGBufferVSToPS { FVertexFactoryInterpolantsVSToPS FactoryInterpolants; FLumenFrontLayerTranslucencyGBufferInterpolantsVSToPS PassInterpolants; INVARIANT_OUTPUT float4 Position : SV_POSITION; }; void MainVS( FVertexFactoryInput Input, out FLumenFrontLayerTranslucencyGBufferVSToPS Output ) { uint EyeIndex = 0; ResolvedView = ResolveView(); FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input); float4 WorldPositionExcludingWPO = VertexFactoryGetWorldPosition(Input, VFIntermediates); float4 WorldPosition = WorldPositionExcludingWPO; float4 ClipSpacePosition; float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates); FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, WorldPosition.xyz, TangentToLocal); ISOLATE { WorldPosition.xyz += GetMaterialWorldPositionOffset(VertexParameters); ApplyMaterialFirstPersonTransform(VertexParameters, WorldPosition.xyz); float4 RasterizedWorldPosition = VertexFactoryGetRasterizedWorldPosition(Input, VFIntermediates, WorldPosition); ClipSpacePosition = INVARIANT(mul(RasterizedWorldPosition, ResolvedView.TranslatedWorldToClip)); Output.Position = INVARIANT(ClipSpacePosition); } Output.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters); } void MainPS( FVertexFactoryInterpolantsVSToPS Interpolants, FLumenFrontLayerTranslucencyGBufferInterpolantsVSToPS PassInterpolants, in INPUT_POSITION_QUALIFIERS float4 SvPosition : SV_Position OPTIONAL_IsFrontFace, out float4 OutTarget0 : SV_Target0 OPTIONAL_OutDepthConservative) { ResolvedView = ResolveView(); FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, SvPosition); FPixelMaterialInputs PixelMaterialInputs; { float4 ScreenPosition = SvPositionToResolvedScreenPosition(SvPosition); float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(SvPosition); CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, TranslatedWorldPosition, TranslatedWorldPosition); } float3 WorldNormal = MaterialParameters.WorldNormal; float Roughness = GetMaterialRoughness(PixelMaterialInputs); #if TEMPLATE_USES_SUBSTRATE { const float3 V = MaterialParameters.CameraVector; const float3 L = MaterialParameters.WorldNormal; // Initialise a Substrate header with normal in registers FSubstrateData SubstrateData = PixelMaterialInputs.GetFrontSubstrateData(); FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader(); SubstratePixelHeader.IrradianceAO.MaterialAO = GetMaterialAmbientOcclusion(PixelMaterialInputs); float TotalCoverage = 1.f; if (SubstratePixelHeader.SubstrateTree.BSDFCount > 0) { const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(false /*bForceFullyRough*/, true /*bRoughDiffuseEnabled*/, 0 /*PeelLayersAboveDepth*/, false/*bRoughnessTracking*/); float3 TotalTransmittancePreCoverage = 0; SubstratePixelHeader.SubstrateUpdateTree(SubstrateData, V, Settings, TotalCoverage, TotalTransmittancePreCoverage); // Clip pixels that will never receive any lumen front material reflections. // We cannot generalise and use GetMaterialClippingVelocity for that because this function clips with a 1/255 threshold...that can result in NaN refelctions if some pixels are not genrated correctly. clip(TotalCoverage <= 0.0f ? -1.0f : 1.0f); // Extract averaged normal and roughness WorldNormal = 0; Roughness = 0; float TopLayerTotalWeight = 0.0f; SUBSTRATE_UNROLL_N(SUBSTRATE_CLAMPED_CLOSURE_COUNT) for (int BSDFIdx = 0; BSDFIdx < SubstratePixelHeader.SubstrateTree.BSDFCount; ++BSDFIdx) { #define CurrentBSDF SubstratePixelHeader.SubstrateTree.BSDFs[BSDFIdx] if (SubstrateIsBSDFVisible(CurrentBSDF)) { FSubstrateAddressing NullSubstrateAddressing = (FSubstrateAddressing)0; // Fake unused in SubstrateCreateBSDFContext when using Forward inline shading FSubstrateBSDFContext SubstrateBSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, CurrentBSDF, NullSubstrateAddressing, V, L); const float Weight = Luminance(CurrentBSDF.LuminanceWeightV); WorldNormal += Weight * SubstrateBSDFContext.N; TopLayerTotalWeight += CurrentBSDF.TopLayerDataWeight; Roughness += CurrentBSDF.TopLayerDataWeight * SubstrateGetBSDFRoughness(CurrentBSDF); } #undef CurrentBSDF } if (any(WorldNormal != 0)) { WorldNormal = normalize(WorldNormal); } Roughness = TopLayerTotalWeight > 0.0f ? Roughness / TopLayerTotalWeight : 0.0f; } } #else // Thin translucent materials are assumed to always have a coverage of 1. #if !MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT clip(PixelMaterialInputs.Opacity <= 0.0f ? -1.0f : 1.0f); #endif #endif // TEMPLATE_USES_SUBSTRATE GetMaterialCoverageAndClipping(MaterialParameters, PixelMaterialInputs); #if OUTPUT_PIXEL_DEPTH_OFFSET ApplyPixelDepthOffsetToMaterialParameters(MaterialParameters, PixelMaterialInputs, OutDepth); #endif // We store (1+roughness*65534)/65535 to make sure w is always greater that 0 where we write which then signifies we need lumen high quality reflections. // The render target is 16-bit unorm and we will still get enough accuracy. OutTarget0 = float4(EncodeNormal(WorldNormal), (1.0f + Roughness * 65534.0f) / 65535.0f); }