Files
UnrealEngine/Engine/Shaders/Private/Substrate/SubstrateForwardLighting.ush
2025-05-18 13:04:45 +08:00

592 lines
27 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#define USE_SUBSTRATE_FORWARD_LIGHTING_COMMON 1
#include "SubstrateLightingCommon.ush"
#include "../LightData.ush"
#if VIRTUAL_SHADOW_MAP
#include "../BlueNoise.ush"
#include "../VirtualShadowMaps/VirtualShadowMapProjectionCommon.ush"
#if SUPPORT_VSM_FOWARD_QUALITY > 0
#include "../VirtualShadowMaps/VirtualShadowMapProjectionFilter.ush"
#include "../VirtualShadowMaps/VirtualShadowMapProjectionDirectional.ush"
#endif // SUPPORT_VSM_FOWARD_QUALITY
#endif // VIRTUAL_SHADOW_MAP
#define FORWARD_PER_PIXEL_SHADING (FORWARD_SHADING || TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING || MATERIAL_SHADINGMODEL_SINGLELAYERWATER)
// Forward declarations
void GetVolumeLightingNonDirectional(float4 AmbientLightingVector, float3 DiffuseColor, inout float3 InterpolatedLighting, out float4 VolumeLighting);
void GetVolumeLightingDirectional(float4 AmbientLightingVector, float3 DirectionalLightingVector, float3 WorldNormal, float3 DiffuseColor, float DirectionalLightingIntensity, inout float3 InterpolatedLighting, out float4 VolumeLighting);
float3 GetWorldBentNormalZero(in FMaterialPixelParameters MaterialParameters);
FShadingOcclusion ApplyBentNormal(
in half3 CameraVector,
in half3 WorldNormal,
in float3 WorldBentNormal0,
in half Roughness,
in half MaterialAO);
void GetPrecomputedIndirectLightingAndSkyLight(
FMaterialPixelParameters MaterialParameters,
FVertexFactoryInterpolantsVSToPS Interpolants,
FBasePassInterpolantsVSToPS BasePassInterpolants,
VTPageTableResult LightmapVTPageTableResult,
bool bEvaluateBackface,
float3 DiffuseDir,
float3 VolumetricLightmapBrickTextureUVs,
out float3 OutDiffuseLighting,
out float3 OutSubsurfaceLighting,
out float OutIndirectIrradiance);
// This code should map to GetForwardDirectLightingSplit
float3 SubstrateForwardLighting(
uint EyeIndex,
float4 SvPosition,
FSubstrateIntegrationSettings Settings,
FBasePassInterpolantsVSToPS BasePassInterpolants,
FVertexFactoryInterpolantsVSToPS Interpolants,
VTPageTableResult LightmapVTPageTableResult,
float3 VolumetricLightmapBrickTextureUVs,
FMaterialPixelParameters MaterialParameters,
float SceneDepth,
float2 ScreenUV,
FSubstratePixelHeader SubstratePixelHeader,
FSubstrateData SubstrateData,
inout float3 OutTransmittancePreCoverage,
inout float OutCoverage
)
{
const uint PrimitiveId = MaterialParameters.PrimitiveId;
const uint2 PixelPos = uint2(SvPosition.xy);
const float Dither = InterleavedGradientNoise(PixelPos, View.StateFrameIndexMod8);
const float3 AbsoluteWorldPosition = WSDemote(GetWorldPosition(MaterialParameters));
const float3 TranslatedWorldPosition = MaterialParameters.WorldPosition_CamRelative;
const float3 LightingPositionOffset = MaterialParameters.LightingPositionOffset;
float3 V = MaterialParameters.CameraVector;
float3 Color = 0;
OutCoverage = 0.0f;
OutTransmittancePreCoverage = 1.0f;
float4 DynamicShadowFactors = 1;
#if MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED
DynamicShadowFactors = GetForwardDynamicShadowFactors(ScreenUV);
#endif
float SpecularScale = 1;
#if TRANSLUCENCY_ANY_VOLUMETRIC
// No specular on volumetric translucency lighting modes
SpecularScale = 0;
#endif
uint PrimitiveLightingChannelMask = GetPrimitive_LightingChannelMask(PrimitiveId);
#if FORWARD_PER_PIXEL_SHADING
// Create the common directional light data use for all layers
const FDirectionalLightData DirectionalLightData = GetDirectionalLightData();
float4 PreviewShadowMapChannelMask = 1;
uint DirLightingChannelMask = LIGHTING_CHANNEL_MASK;
FDeferredLightData DirLightData = ConvertToDeferredLight(DirectionalLightData, SpecularScale, PreviewShadowMapChannelMask, DirLightingChannelMask);
// We want to force the directional light shadow when using water material to see shadow on the water. This could be an option later.
#if DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW
float4 DirLightAttenuation = float4(1, 1, 1, 1);
#elif ((MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER)
float DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors);
// In the forward shading path we can't separate per-object shadows from CSM, since we only spend one light attenuation channel per light
// If CSM is enabled (distance fading to precomputed shadowing is active), treat all of our dynamic shadowing as whole scene shadows that will be faded out at the max CSM distance
// If CSM is not enabled, allow our dynamic shadowing to coexist with precomputed shadowing
float PerObjectShadowing = DirLightData.DistanceFadeMAD.y < 0.0f ? 1.0f : DynamicShadowing;
float WholeSceneShadowing = DirLightData.DistanceFadeMAD.y < 0.0f ? DynamicShadowing : 1.0f;
float4 DirLightAttenuation = float4(WholeSceneShadowing.xx, PerObjectShadowing.xx);
#else
DirLightData.ShadowedBits = 1;
DirLightData.ShadowMapChannelMask.x = 1;
bool bUnused = false;
float DirLightDynamicShadowFactor = ComputeDirectionalLightDynamicShadowing(TranslatedWorldPosition, SceneDepth, bUnused);
#if VIRTUAL_SHADOW_MAP
BRANCH
if ( ForwardLightStruct.DirectionalLightVSM != INDEX_NONE )
{
#if SUPPORT_VSM_FOWARD_QUALITY == 1
{
const FLightShaderParameters DirectionalLight = ConvertToLightShaderParameters(DirLightData);
const float ScreenRayLengthWorld = VirtualShadowMap.ScreenRayLength * View.ClipToView[1][1] * SceneDepth;
float SMRTRayOffset = ScreenRayLengthWorld;
// Use the surface normal instead of the layer's normal, for a single evaluation before runing throught the SubstrateTree
const half3 WorldNormal = normalize(MaterialParameters.TangentToWorld[2]);
FVirtualShadowMapSampleResult VirtualShadowMapSample = TraceDirectional(
ForwardLightStruct.DirectionalLightVSM,
DirectionalLight,
PixelPos,
SceneDepth,
TranslatedWorldPosition,
SMRTRayOffset,
Dither,
WorldNormal);
FilterVirtualShadowMapSampleResult(PixelPos, VirtualShadowMapSample);
DirLightDynamicShadowFactor *= VirtualShadowMapSample.ShadowFactor;
}
#else
{
FVirtualShadowMapSampleResult VirtualShadowMapSample = SampleVirtualShadowMapDirectional(ForwardLightStruct.DirectionalLightVSM, TranslatedWorldPosition);
DirLightDynamicShadowFactor *= VirtualShadowMapSample.ShadowFactor;
}
#endif
}
#endif
float4 DirLightAttenuation = float4(DirLightDynamicShadowFactor.x, DirLightDynamicShadowFactor.x, 1, 1);
#endif
#endif // FORWARD_PER_PIXEL_SHADING
uint GridIndex = 0;
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
GridIndex = ComputeLightGridCellIndex((uint2)((MaterialParameters.SvPosition.xy - ResolvedView.ViewRectMin.xy) * View.LightProbeSizeRatioAndInvSizeRatio.zw), MaterialParameters.SvPosition.w, EyeIndex);
#endif
if (SubstratePixelHeader.SubstrateTree.BSDFCount > 0)
{
// Write Irradiance/AO data into header in order to be retrieve correctly during lighting
#if SUBSTRATE_INLINE_SHADING
HEADER_SETIRRADIANCE_AO(SubstratePixelHeader.State, SubstratePackIrradianceAndOcclusion(SubstratePixelHeader.IrradianceAO, 0));
#endif
// Update tree (coverage/transmittance/luminace weights)
SubstratePixelHeader.SubstrateUpdateTree(SubstrateData, V, Settings, OutCoverage, OutTransmittancePreCoverage);
//
// Forward lighting
//
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
// Starting with environment lighting, the context does not specify a light
FSubstrateBSDFContext SubstrateBSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, CurrentBSDF, NullSubstrateAddressing, V);
////
//// Evaluate environment lighting
////
// Compute the bent normal from the BSDF normal
const float Roughness = SubstrateGetBSDFRoughness(CurrentBSDF);
const FShadingOcclusion ShadingOcclusion = ApplyBentNormal(MaterialParameters.CameraVector, SubstrateBSDFContext.N, GetWorldBentNormalZero(MaterialParameters), Roughness, SubstrateGetAO(SubstratePixelHeader));
float IndirectOcclusion = 1.0f;
float IndirectIrradiance = 0.0f;
// 1. Diffuse Sky evaluation using bent normal
{
// Update a context specific for environment lighting
FSubstrateBSDFContext EnvBSDFContext = SubstrateBSDFContext;
EnvBSDFContext.N = ShadingOcclusion.BentNormal;
EnvBSDFContext.SubstrateUpdateBSDFContext(EnvBSDFContext.L);
// And evaluate diffuse parameters
FSubstrateEnvLightResult SubstrateEnvLight = SubstrateEvaluateForEnvLight(EnvBSDFContext, false/*bEnableSpecular*/, Settings);
float3 DiffuseNormal = SubstrateEnvLight.DiffuseNormal;
float3 DiffuseColorForIndirect = SubstrateEnvLight.DiffuseWeight;
float3 SubsurfaceColorForIndirect = SubstrateEnvLight.DiffuseBackFaceWeight;
// Evaluate diffuse lighting
if (any((DiffuseColorForIndirect + SubsurfaceColorForIndirect) > 0.0f))
{
const bool bEvaluateBackface = any(SubsurfaceColorForIndirect > 0.0);
float3 DiffuseIndirectLighting = 0.0f;
float3 SubsurfaceIndirectLighting = 0.0f;
#if (MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE || MATERIALBLENDING_MODULATE) && PROJECT_SUPPORTS_LUMEN && !FORWARD_SHADING
if (IsLumenTranslucencyGIEnabled())
{
// Lumen Dynamic GI + shadowed Skylight
FTwoBandSHVectorRGB TranslucencyGISH = GetTranslucencyGIVolumeLighting(MaterialParameters.AbsoluteWorldPosition, ResolvedView.WorldToClip, true);
#if TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL
FOneBandSHVectorRGB TranslucencyGISH1;
TranslucencyGISH1.R.V = TranslucencyGISH.R.V.x;
TranslucencyGISH1.G.V = TranslucencyGISH.G.V.x;
TranslucencyGISH1.B.V = TranslucencyGISH.B.V.x;
FOneBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH1(1);
DiffuseIndirectLighting += max(float3(0,0,0), DotSH1(TranslucencyGISH1, DiffuseTransferSH)) / PI;
#else
// Diffuse convolution
FTwoBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH(DiffuseNormal, 1);
DiffuseIndirectLighting += max(half3(0,0,0), DotSH(TranslucencyGISH, DiffuseTransferSH)) / PI;
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
if (bEvaluateBackface)
{
FTwoBandSHVector SubsurfaceTransferSH = CalcDiffuseTransferSH(-DiffuseNormal, 1);
SubsurfaceIndirectLighting += max(half3(0,0,0), DotSH(TranslucencyGISH, SubsurfaceTransferSH)) / PI;
}
#endif
#endif
}
else
#endif
if (UseBasePassSkylight > 0)
{
GetPrecomputedIndirectLightingAndSkyLight(
MaterialParameters,
Interpolants,
BasePassInterpolants,
LightmapVTPageTableResult,
bEvaluateBackface,
DiffuseNormal,
VolumetricLightmapBrickTextureUVs,
DiffuseIndirectLighting,
SubsurfaceIndirectLighting,
IndirectIrradiance);
}
#if FORWARD_SHADING && (MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED)
float2 NearestResolvedDepthScreenUV = CalculateNearestResolvedDepthScreenUV(ScreenUV, MaterialParameters.ScreenPosition.w);
IndirectOcclusion = GetIndirectOcclusion(NearestResolvedDepthScreenUV, SubstratePixelHeader.HasDynamicIndirectShadowCasterRepresentation());
DiffuseIndirectLighting *= IndirectOcclusion;
SubsurfaceIndirectLighting *= IndirectOcclusion;
IndirectIrradiance *= IndirectOcclusion;
#endif
// For diffuse, we specify a perpendicular to the surface light direction for the transmittance to light to not be view dependent.
const float DiffuseEnvLightingNoL = 1.0f;
Color += (DiffuseIndirectLighting * DiffuseColorForIndirect + SubsurfaceIndirectLighting * SubsurfaceColorForIndirect) *
LuminanceWeight(DiffuseEnvLightingNoL, CurrentBSDF) * AOMultiBounce(SubstrateEnvLight.DiffuseColor, ShadingOcclusion.DiffOcclusion);
}
}
// 2. Specular evaluation (using regular normal)
#if FORWARD_PER_PIXEL_SHADING || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME
// Every components of forward shading reflection (Sky, SSR, Lumen) are enabled/disabled within GetImageBasedReflectionSpecular.
{
// Evaluate specular parameters without bent normal
FSubstrateEnvLightResult SubstrateEnvLight = SubstrateEvaluateForEnvLight(SubstrateBSDFContext, true/*bEnableSpecular*/, Settings);
// Evaluate specular lighting for the main lobe
if (any(SubstrateEnvLight.SpecularWeight > 0.0f))
{
int SingleCaptureIndex = GetPrimitiveData(MaterialParameters).SingleCaptureIndex;
Color += GetImageBasedReflectionSpecular(MaterialParameters, SubstrateEnvLight.SpecularDirection, SubstrateEnvLight.SpecularSafeRoughness, IndirectIrradiance, GridIndex, SingleCaptureIndex) *
SubstrateEnvLight.SpecularWeight * IndirectOcclusion * LuminanceWeight(SubstrateBSDFContext, CurrentBSDF) * AOMultiBounce(SubstrateEnvLight.SpecularColor, ShadingOcclusion.SpecOcclusion);
}
// And for the second lobe if needed
if (any(SubstrateEnvLight.SpecularHazeWeight > 0.0f))
{
int SingleCaptureIndex = GetPrimitiveData(MaterialParameters).SingleCaptureIndex;
Color += GetImageBasedReflectionSpecular(MaterialParameters, SubstrateEnvLight.SpecularHazeDirection, SubstrateEnvLight.SpecularHazeSafeRoughness, IndirectIrradiance, GridIndex, SingleCaptureIndex) *
SubstrateEnvLight.SpecularHazeWeight * IndirectOcclusion * LuminanceWeight(SubstrateBSDFContext, CurrentBSDF) * AOMultiBounce(SubstrateEnvLight.SpecularColor, ShadingOcclusion.SpecOcclusion);
}
}
#endif
////
//// Evaluate translucent lighting volume / vertex lighting.
////
// In deferred shading, the translucenyt volume is used by
// - TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL
// - TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_DIRECTIONAL
// - TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL
// - TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL
// - TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME
// In forward, things change (for some reasons...)
// - TRANSLUCENCY_PERVERTEX_FORWARD_SHADING make sure TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL and TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_DIRECTIONAL works the same way.
// - TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL will follow the SubstrateForwardLightingCommon path and directionality is removed using NON_DIRECTIONAL_DIRECT_LIGHTING
// - TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL will be same as TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING but without the environment specular contribution
// - TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME becomes the same as TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING
// SUBSTRATE_TODO simplify all that and have forward map to the same technique as in deferred.
#if TRANSLUCENCY_PERVERTEX_FORWARD_SHADING || TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_DIRECTIONAL || (!FORWARD_SHADING && (TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME))
float4 VolumeLighting;
float3 SurfaceLighting = 0;
float3 InnerVolumeUVs;
float3 OuterVolumeUVs;
float FinalLerpFactor;
ComputeVolumeUVs(TranslatedWorldPosition, LightingPositionOffset, InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
FSubstrateEvaluateResult BSDFEvaluate = SubstrateEvaluateBSDF(SubstrateBSDFContext, Settings);
#if TRANSLUCENCY_PERVERTEX_FORWARD_SHADING
SurfaceLighting = BasePassInterpolants.VertexDiffuseLighting * BSDFEvaluate.DiffuseColor;
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL
// ForwardShadingNote: when forward shading is enabled, this will follow the special TRANSLUCENCY_PERVERTEX_FORWARD_SHADING path above
GetVolumeLightingNonDirectional(float4(BasePassInterpolants.AmbientLightingVector, 1), BSDFEvaluate.DiffuseColor, SurfaceLighting, VolumeLighting);
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_DIRECTIONAL
// ForwardShadingNote: when forward shading is enabled, this will follow the special TRANSLUCENCY_PERVERTEX_FORWARD_SHADING path above
GetVolumeLightingDirectional(float4(BasePassInterpolants.AmbientLightingVector, 1), BasePassInterpolants.DirectionalLightingVector, SubstrateBSDFContext.N, BSDFEvaluate.DiffuseColor, GetMaterialTranslucencyDirectionalLightingIntensity(), SurfaceLighting, VolumeLighting);
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL && !FORWARD_SHADING
//ForwardShadingNote: when forward shading is enabled, SubstrateForwardLightingCommon path will be used
float4 AmbientLightingVector = GetAmbientLightingVectorFromTranslucentLightingVolume(InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
GetVolumeLightingNonDirectional(AmbientLightingVector, BSDFEvaluate.DiffuseColor, SurfaceLighting, VolumeLighting);
#elif (TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME) && !FORWARD_SHADING
//ForwardShadingNote: when forward shading is enabled, SubstrateForwardLightingCommon path will be used
float4 AmbientLightingVector = GetAmbientLightingVectorFromTranslucentLightingVolume(InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
float3 DirectionalLightingVector = GetDirectionalLightingVectorFromTranslucentLightingVolume(InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
GetVolumeLightingDirectional(AmbientLightingVector, DirectionalLightingVector, SubstrateBSDFContext.N, BSDFEvaluate.DiffuseColor, GetMaterialTranslucencyDirectionalLightingIntensity(), SurfaceLighting, VolumeLighting);
#endif // TRANSLUCENCY_
// SUBSTRATE_TODO: we should simply remove this self shadow code path TRANSLUCENT_SELF_SHADOWING and only use FOM to shadow the ? Translucent shadow should .
#if (TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME) && TRANSLUCENT_SELF_SHADOWING
// Only apply self shadowing if the shadow hasn't faded out completely
if (TranslucentSelfShadow.DirectionalLightColor.a > 0)
{
// Determine the shadow space position
// Apply a stable offset to the world position used for shadowing, which blurs out high frequency details in the shadowmap with many layers
float4 HomogeneousShadowPosition = mul(float4(AbsoluteWorldPosition + LightingPositionOffset * View.TranslucencyLightingVolumeInvSize[0].w, 1), TranslucentSelfShadow.WorldToShadowMatrix);
float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w;
float ShadowZ = 1 - HomogeneousShadowPosition.z;
// Lookup the shadow density at the point being shaded
float3 ShadowDensity = CalculateTranslucencyShadowingDensity(ShadowUVs, ShadowZ) / GetMaterialTranslucentMultipleScatteringExtinction();
// Compute colored transmission based on the density that the light ray passed through
float3 SelfShadowing = saturate(exp(-ShadowDensity * GetMaterialTranslucentSelfShadowDensityScale()));
// Compute a second shadow gradient to add interesting information in the shadowed area of the first
// This is a stop gap for not having self shadowing from other light sources
float3 SelfShadowing2 = lerp(float3(1, 1, 1), saturate(exp(-ShadowDensity * GetMaterialTranslucentSelfShadowSecondDensityScale())), GetMaterialTranslucentSelfShadowSecondOpacity());
SelfShadowing = SelfShadowing * SelfShadowing2;
// Force unshadowed if we read outside the valid area of the shadowmap atlas
// This can happen if the particle system's bounds don't match its visible area
FLATTEN
if (any(ShadowUVs < TranslucentSelfShadow.ShadowUVMinMax.xy || ShadowUVs > TranslucentSelfShadow.ShadowUVMinMax.zw))
{
SelfShadowing = 1;
}
// The volume lighting already contains the contribution of the directional light,
// So calculate the amount of light to remove from the volume lighting in order to apply per-pixel self shadowing
// VolumeLighting.a stores all attenuation and opaque shadow factors
float3 SelfShadowingCorrection = TranslucentSelfShadow.DirectionalLightColor.rgb * VolumeLighting.a * (1 - SelfShadowing);
// Combine backscattering and directional light self shadowing
SurfaceLighting = (BSDFEvaluate.DiffuseColor * max(VolumeLighting.rgb - SelfShadowingCorrection, 0));
}
#endif
const float LightVolumeNoL = 1.0f;
Color += SurfaceLighting * LuminanceWeight(LightVolumeNoL, CurrentBSDF) + BSDFEvaluate.EmissivePathValue * CurrentBSDF.LuminanceWeightV;
#elif FORWARD_PER_PIXEL_SHADING
////
//// Evaluate emissive
////
Color += BSDF_GETEMISSIVE(CurrentBSDF) * CurrentBSDF.LuminanceWeightV;
////
//// Evaluate the single directional light selected for forward lighting.
////
BRANCH
if (DirectionalLightData.HasDirectionalLight
#if SUBSTRATE_TRANSLUCENT_MATERIAL
&& DirectionalLightData.bAffectsTranslucentLighting > 0
#endif
)
{
float3 DirLightL = DirLightData.Direction; // Already normalized
float3 ToDirLight = DirLightL;
float DirLightMask = 1;
if (DirLightData.bRadialLight)
{
DirLightMask = GetLocalLightAttenuation(TranslatedWorldPosition, DirLightData, ToDirLight, DirLightL);
}
float DirectionalLightCloudShadow = 1.0f;
#if NEEDS_BASEPASS_CLOUD_SHADOW_INTERPOLATOR
DirectionalLightCloudShadow = BasePassInterpolants.VertexCloudShadow;
#endif
SubstrateBSDFContext.SubstrateUpdateBSDFContext(ToDirLight);
FSubstrateEvaluateResult BSDFEvaluate = (FSubstrateEvaluateResult)0;
Color += SubstrateForwardLightingCommon(
Dither,
Settings,
DirLightData,
ToDirLight,
DirLightMask,
DirLightAttenuation,
InitRectTexture(),
DirLightingChannelMask,
PrimitiveLightingChannelMask,
GetPrecomputedShadowFactors(SubstratePixelHeader, TranslatedWorldPosition),
TranslatedWorldPosition,
SceneDepth,
LuminanceWeight(SubstrateBSDFContext, CurrentBSDF),
SubstratePixelHeader,
SubstrateBSDFContext,
BSDFEvaluate) * DirectionalLightCloudShadow;
}
////
//// Evaluate local lights
////
#if !DISABLE_FORWARD_LOCAL_LIGHTS && (FORWARD_SHADING || TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING) // Forbidden for Single Layer Water
// Basic implementation for FORWARD_LOCAL_LIGHTS where local lights are reloaded per BSDF layer. It is fast by default when layer==1.
const FCulledLightsGridHeader CulledLightsGridHeader = GetCulledLightsGridHeader(GridIndex);
// Limit max to ForwardLightStruct.NumLocalLights.
// This prevents GPU hangs when the PS tries to read from uninitialized NumCulledLightsGrid buffer
const uint NumLightsInGridCell = min(CulledLightsGridHeader.NumLights, GetMaxLightsPerCell());
LOOP
for (uint GridLightListIndex = 0; GridLightListIndex < NumLightsInGridCell; GridLightListIndex++)
{
const FLocalLightData LocalLight = GetLocalLightDataFromGrid(CulledLightsGridHeader.DataStartIndex + GridLightListIndex, EyeIndex);
#if MATERIALBLENDING_ANY_TRANSLUCENT
if(UnpackAffectsTranslucentLighting(LocalLight) == 0)
{
continue;
}
#endif
half4 PreviewShadowMapChannelMask = 1;
uint LocalLightChannelMask = LIGHTING_CHANNEL_MASK;
FDeferredLightData LightData = ConvertToDeferredLight(LocalLight, 1.0f /*SpecularScale*/, PreviewShadowMapChannelMask, LocalLightChannelMask);
#if USE_IES_PROFILE
LightData.Color *= ComputeLightProfileMultiplier(TranslatedWorldPosition, LightData.TranslatedWorldPosition, -LightData.Direction, LightData.Tangent, LightData.IESAtlasIndex);
#endif
// Rect light optionally supported in forward.
// * This is not done explicitely in the legacy path (resulting in no lighting) but we do it for Substrate in order to avoid visual artefact.
// * This can be removed when LocalLight properly supports rect lights.
if (LightData.bRectLight && !SUPPORT_RECTLIGHT_ON_FORWARD_LIT_TRANSLUCENT)
{
continue;
}
// When disabled, force the compiler to remove the texture atlas sampling to avoid taking an extra texture sampler
#if !SUPPORT_RECTLIGHT_ON_FORWARD_LIT_TRANSLUCENT
LightData.bRectLight = false;
#endif
const FRectTexture LocalRectTexture = ConvertToRectTexture(LightData);
float DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors);
float4 LightAttenuation = float4(1, 1, DynamicShadowing.x, DynamicShadowing.x);
float3 L = LightData.Direction; // Already normalized
float3 ToLight = L;
float LightMask = 1;
if (LightData.bRadialLight)
{
LightMask = GetLocalLightAttenuation(TranslatedWorldPosition, LightData, ToLight, L);
}
#if VIRTUAL_SHADOW_MAP && SUPPORT_SHADOWED_LOCAL_LIGHT_ON_FORWARD_LIT_TRANSLUCENT
BRANCH
if (LocalLight.Internal.VirtualShadowMapId != INDEX_NONE)
{
float DynamicShadowFactor = 1.f;
LightData.ShadowedBits = 1;
#if SUPPORT_VSM_FOWARD_QUALITY == 1
{
const FLightShaderParameters LocalLightShaderParameters = ConvertToLightShaderParameters(LightData);
const float ScreenRayLengthWorld = VirtualShadowMap.ScreenRayLength * View.ClipToView[1][1] * Depth;
float SMRTRayOffset = ScreenRayLengthWorld;
// Use the surface normal instead of the layer's normal, for a single evaluation before runing throught the SubstrateTree
const half3 WorldNormal = normalize(MaterialParameters.TangentToWorld[2]);
FVirtualShadowMapSampleResult VirtualShadowMapSample = TraceLocalLight(
LocalLight.VirtualShadowMapId,
LocalLightShaderParameters,
PixelPos,
SceneDepth,
TranslatedWorldPosition,
SMRTRayOffset,
Dither,
WorldNormal);
FilterVirtualShadowMapSampleResult(PixelPos, VirtualShadowMapSample);
DynamicShadowFactor *= VirtualShadowMapSample.ShadowFactor;
}
#else
{
FVirtualShadowMapSampleResult VirtualShadowMapSample = SampleVirtualShadowMapLocal(LocalLight.Internal.VirtualShadowMapId, TranslatedWorldPosition);
DynamicShadowFactor *= VirtualShadowMapSample.ShadowFactor;
}
#endif
LightAttenuation = DynamicShadowFactor;
}
#endif
// Update the Substrate BSDF context accordgin to the new L
SubstrateBSDFContext.SubstrateUpdateBSDFContext(ToLight);
FSubstrateEvaluateResult BSDFEvaluate = (FSubstrateEvaluateResult)0;
Color += SubstrateForwardLightingCommon(
Dither,
Settings,
LightData,
ToLight,
LightMask,
LightAttenuation,
LocalRectTexture,
LocalLightChannelMask,
PrimitiveLightingChannelMask,
GetPrecomputedShadowFactors(SubstratePixelHeader, TranslatedWorldPosition),
TranslatedWorldPosition,
SceneDepth,
LuminanceWeight(SubstrateBSDFContext, CurrentBSDF),
SubstratePixelHeader,
SubstrateBSDFContext,
BSDFEvaluate);
}
#endif // !DISABLE_FORWARD_LOCAL_LIGHTS
#endif // Lighting technique
}// SubstrateIsBSDFVisible
#undef CurrentBSDF
}
}
return Color;
}