Files
UnrealEngine/Engine/Shaders/Private/ReflectionEnvironmentPixelShader.usf
2025-05-18 13:04:45 +08:00

611 lines
23 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
ReflectionEnvironmentComputeShaders - functionality to apply local cubemaps.
=============================================================================*/
#if SUBSTRATE_ENABLED
#define SUBSTRATE_INLINE_SHADING 0
#if SUBSTRATE_TILETYPE == 0
#define SUBSTRATE_FASTPATH 1
#elif SUBSTRATE_TILETYPE == 1
#define SUBSTRATE_SINGLEPATH 1
#elif SUBSTRATE_TILETYPE == 2
// COMPLEX PATH
#elif SUBSTRATE_TILETYPE == 3
// COMPLEX PATH
#define SUBSTRATE_COMPLEXSPECIALPATH 1
#else
#error Substrate tile type non-implemented
#endif
#endif
#include "Common.ush"
#include "DeferredShadingCommon.ush"
#include "BRDF.ush"
#include "ReflectionEnvironmentShared.ush"
#include "SkyLightingShared.ush"
#include "SkyLightingDiffuseShared.ush"
#include "DistanceFieldAOShared.ush"
#include "ShadingModels.ush"
#include "LightGridCommon.ush"
#include "SceneTextureParameters.ush"
#include "ClearCoatCommon.ush"
#define REFLECTION_COMPOSITE_USE_BLENDED_REFLECTION_CAPTURES 1
#define REFLECTION_COMPOSITE_SUPPORT_SKYLIGHT_BLEND 1
#define USE_SUBSTRATE_ENV_LIGHTING_COMMON 1
#include "ReflectionEnvironmentComposite.ush"
#include "/Engine/Private/Substrate/SubstrateEvaluation.ush"
#include "/Engine/Private/Substrate/SubstrateLightingCommon.ush"
#include "Lumen/LumenReflectionsCombine.ush"
#define REFLECTION_SOURCE_SSR 0
#define REFLECTION_SOURCE_TILED_SSR 1
#define REFLECTION_SOURCE_LUMEN_STANDALONE 2
#ifndef REFLECTION_SOURCE_TYPE
#define REFLECTION_SOURCE_TYPE REFLECTION_SOURCE_SSR
#endif
#if REFLECTION_SOURCE_TYPE != REFLECTION_SOURCE_LUMEN_STANDALONE
#include "ScreenSpaceReflectionTileCommons.ush"
#endif
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE
Texture2DArray LumenReflectionTexture;
SamplerState LumenReflectionTextureSampler;
#else
Texture2D ReflectionTexture;
SamplerState ReflectionTextureSampler;
#endif
#if ENABLE_DYNAMIC_SKY_LIGHT
#include "VolumetricCloudCommon.ush"
Texture2D<float3> CloudSkyAOTexture;
SamplerState CloudSkyAOSampler;
float4x4 CloudSkyAOWorldToLightClipMatrix;
float CloudSkyAOFarDepthKm;
int CloudSkyAOEnabled;
#endif
Texture2D AmbientOcclusionTexture;
SamplerState AmbientOcclusionSampler;
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_TILED_SSR
uint2 SSRTiledViewRes;
StructuredBuffer<uint> SSRTileMaskBuffer;
#endif
float3 GatherRadiance(float CompositeAlpha, float3 TranslatedWorldPosition, float3 RayDirection, float Roughness, float3 BentNormal, float IndirectIrradiance, uint ShadingModelID, uint NumCulledReflectionCaptures, uint CaptureDataStartIndex)
{
// Indirect occlusion from DFAO, which should be applied to reflection captures and skylight specular, but not SSR
float IndirectSpecularOcclusion = 1.0f;
float3 ExtraIndirectSpecular = 0;
#if SUPPORT_DFAO_INDIRECT_OCCLUSION
float IndirectDiffuseOcclusion;
GetDistanceFieldAOSpecularOcclusion(BentNormal, RayDirection, Roughness, ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE, IndirectSpecularOcclusion, IndirectDiffuseOcclusion, ExtraIndirectSpecular);
// Apply DFAO to IndirectIrradiance before mixing with indirect specular
IndirectIrradiance *= IndirectDiffuseOcclusion;
#endif
const bool bCompositeSkylight = true;
return CompositeReflectionCapturesAndSkylightTWS(
CompositeAlpha,
TranslatedWorldPosition,
RayDirection,
Roughness,
IndirectIrradiance,
IndirectSpecularOcclusion,
ExtraIndirectSpecular,
NumCulledReflectionCaptures,
CaptureDataStartIndex,
0,
bCompositeSkylight);
}
float4 CompositeReflections(float4 ReflectionInput, float2 BufferUV, float InRoughness, uint ShadingModelID)
{
float4 Lighting = float4(0, 0, 0, 1);
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE
const bool bHasBackfaceDiffuse = ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE || ShadingModelID == SHADINGMODELID_SUBSURFACE;
const float FadeAlpha = ShadingModelID == SHADINGMODELID_CLEAR_COAT ? 1.0f : LumenCombineReflectionsAlpha(InRoughness, bHasBackfaceDiffuse);
// Must branch as Lumen Reflections can be uninitialized where not needed and contain NaN
if (FadeAlpha > 0.0f)
{
Lighting.rgb = ReflectionInput.xyz * FadeAlpha;
Lighting.a = 1 - FadeAlpha;
}
#else
Lighting.rgb = ReflectionInput.rgb;
Lighting.a = 1 - ReflectionInput.a;
#endif
return Lighting;
}
float3 ReflectionEnvironment(FGBufferData GBuffer, float AmbientOcclusion, float2 BufferUV, float2 ScreenPosition, float4 SvPosition, float3 BentNormal, float3 SpecularColor, uint ShadingModelID)
{
float4 Color = float4(0, 0, 0, 1);
float IndirectIrradiance = GBuffer.IndirectIrradiance;
#if ENABLE_SKY_LIGHT && ALLOW_STATIC_LIGHTING
BRANCH
// Add in diffuse contribution from dynamic skylights so reflection captures will have something to mix with
if (ReflectionStruct.SkyLightParameters.y > 0 && ReflectionStruct.SkyLightParameters.z > 0)
{
IndirectIrradiance += GetDynamicSkyIndirectIrradiance(BentNormal, GBuffer.WorldNormal);
}
#endif
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, GBuffer.Depth), GBuffer.Depth, 1), View.ScreenToTranslatedWorld).xyz;
float3 CameraToPixel = GetCameraVectorFromTranslatedWorldPosition(TranslatedWorldPosition);
float3 ReflectionVector = reflect(CameraToPixel, GBuffer.WorldNormal);
float3 V = -CameraToPixel;
float3 N = GBuffer.WorldNormal;
const float3 SavedTopLayerNormal = N;
#if SUPPORTS_ANISOTROPIC_MATERIALS
ModifyGGXAnisotropicNormalRoughness(GBuffer.WorldTangent, GBuffer.Anisotropy, GBuffer.Roughness, N, V);
#endif
float3 R = 2 * dot( V, N ) * N - V;
float NoV = saturate( dot( N, V ) );
// Point lobe in off-specular peak direction
R = GetOffSpecularPeakReflectionDir(N, R, GBuffer.Roughness);
// Sample input reflection texture that may contain SSR, planar reflections, RT reflections or Lumen Reflections
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE
float4 ReflectionInput = Texture2DArraySample(LumenReflectionTexture, LumenReflectionTextureSampler, float3(BufferUV, 0));
#elif REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_SSR
float4 ReflectionInput = Texture2DSample(ReflectionTexture, ReflectionTextureSampler, BufferUV);
#else // REFLECTION_SOURCE_TILED_SSR
const uint2 PixelPos = uint2(SvPosition.xy);
bool bSSRTileUsed = IsSSRTileUsed(PixelPos, SSRTiledViewRes, SSRTileMaskBuffer);
float4 ReflectionInput = 0;
if (bSSRTileUsed)
{
ReflectionInput = Texture2DSample(ReflectionTexture, ReflectionTextureSampler, BufferUV);
}
#endif
Color = CompositeReflections(ReflectionInput, BufferUV, GBuffer.Roughness, ShadingModelID);
if(GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT )
{
const float ClearCoat = GBuffer.CustomData.x;
Color = lerp( Color, float4(0,0,0,1), ClearCoat );
#if CLEAR_COAT_BOTTOM_NORMAL
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1);
const float3 BottomEffectiveNormal = ClearCoatUnderNormal;
R = 2 * dot( V, ClearCoatUnderNormal ) * ClearCoatUnderNormal - V;
#endif
}
float AO = GBuffer.GBufferAO * AmbientOcclusion;
float RoughnessSq = GBuffer.Roughness * GBuffer.Roughness;
float SpecularOcclusion = GetSpecularOcclusion(NoV, RoughnessSq, AO);
Color.a *= SpecularOcclusion;
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), GBuffer.Depth, 0);
FCulledReflectionCapturesGridHeader CulledReflectionCapturesGridHeader = GetCulledReflectionCapturesGridHeader(GridIndex);
uint NumCulledReflectionCaptures = CulledReflectionCapturesGridHeader.NumReflectionCaptures;
uint CaptureDataStartIndex = CulledReflectionCapturesGridHeader.DataStartIndex;
#else
uint CaptureDataStartIndex = 0;
uint NumCulledReflectionCaptures = 0;
#endif
#if USE_ENERGY_CONSERVATION
const FBxDFEnergyTerms EnergyTerms = ComputeGGXSpecEnergyTerms(GBuffer.Roughness, NoV, GBuffer.SpecularColor);
#endif
//Top of regular reflection or bottom layer of clear coat.
Color.rgb += View.PreExposure * GatherRadiance(Color.a, TranslatedWorldPosition, R, GBuffer.Roughness, BentNormal, IndirectIrradiance, GBuffer.ShadingModelID, NumCulledReflectionCaptures, CaptureDataStartIndex);
BRANCH
if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
{
const float ClearCoat = GBuffer.CustomData.x;
const float ClearCoatRoughness = GBuffer.CustomData.y;
// Restore saved values needed for the top layer.
GBuffer.WorldNormal = SavedTopLayerNormal;
// Recompute some values unaffected by anistropy for the top layer
N = GBuffer.WorldNormal;
R = 2 * dot(V, N) * N - V;
NoV = saturate(dot(N, V));
R = GetOffSpecularPeakReflectionDir(N, R, ClearCoatRoughness);
// TODO EnvBRDF should have a mask param
#if USE_ENERGY_CONSERVATION
Color.rgb *= EnergyTerms.E;
#else
// Hack: Ensures when clear coat is >0, grazing angle does not get too much energy,
// but preserve response at normal incidence
float2 AB = PreIntegratedGF.SampleLevel(PreIntegratedGFSampler, float2(NoV, GBuffer.Roughness), 0).rg;
Color.rgb *= SpecularColor * AB.x + AB.y * saturate(50 * SpecularColor.g) * (1 - ClearCoat);
#endif
// F_Schlick
const float CoatF0 = 0.04f;
#if USE_ENERGY_CONSERVATION
float F = ComputeGGXSpecEnergyTerms(ClearCoatRoughness, NoV, CoatF0).E.x;
#else
float F = EnvBRDF(CoatF0, ClearCoatRoughness, NoV).x;
#endif
F *= ClearCoat;
float LayerAttenuation = (1 - F);
Color.rgb *= LayerAttenuation;
Color.a = F;
Color.rgb += ReflectionInput.rgb * F;
Color.a *= 1 - ReflectionInput.a;
Color.a *= SpecularOcclusion;
float3 TopLayerR = 2 * dot( V, N ) * N - V;
Color.rgb += View.PreExposure * GatherRadiance(Color.a, TranslatedWorldPosition, TopLayerR, ClearCoatRoughness, BentNormal, IndirectIrradiance, GBuffer.ShadingModelID, NumCulledReflectionCaptures, CaptureDataStartIndex);
}
else
{
#if USE_ENERGY_CONSERVATION
Color.rgb *= EnergyTerms.E;
#else
Color.rgb *= EnvBRDF( SpecularColor, GBuffer.Roughness, NoV );
#endif
}
// Transform NaNs to black, transform negative colors to black.
return -min(-Color.rgb, 0.0);
}
float GetCloudVolumetricAOShadow(in float3 TranslatedWorldPosition)
{
// Ideally we would compute spatially how much of the sky+cloud is visible for each point in the world. But we evaluate the sky light only once at the sky light component position as of today.
// To add some spatial variation, we can affect the sky light diffuse contribution according to cloud occlusion from above.
// This is an approximation because clouds are also occluding the sky in the sky light capture (a bit of a double contribution then). but it does help by adding spatially varying details.
#if 0 // DISABLED for now because it has artefact with specular not being affected (and thus looking too bright which can be confusing for users).
// NOTE: Consider wrapping this inside a define when enabled. Otherwise, perf will regress on less powerful platforms
if (CloudSkyAOEnabled)
{
float OutOpticalDepth = 0.0f;
return GetCloudVolumetricShadow(TranslatedWorldPosition, CloudSkyAOWorldToLightClipMatrix, CloudSkyAOFarDepthKm, CloudSkyAOTexture, CloudSkyAOSampler, OutOpticalDepth);
}
#endif
return 1.0f;
}
#if SUBTRATE_GBUFFER_FORMAT==1
struct FSSRContribution
{
float3 SSRTopLayerEnvBRDF;
float SSRReductionFactor;
};
FSSRContribution InitSSRContribution()
{
FSSRContribution Out;
Out.SSRReductionFactor = 1.0f;
Out.SSRTopLayerEnvBRDF = 0.0f;
return Out;
}
void GetSSSRContribution(
in FSubstrateEnvLightResult SubstrateEnvLight,
in FSubstrateBSDF BSDF,
in float3 BSDFThroughput,
inout FSSRContribution Out)
{
// The specular path weight applied on SSR. It must account for throughput even for top surface because it also contains coverage.
Out.SSRTopLayerEnvBRDF += BSDFThroughput * SubstrateEnvLight.SSRSpecularWeight;
#if SUBSTRATE_FASTPATH==0
if (BSDF_GETISTOPLAYER(BSDF) && BSDF_GETHASHAZINESS(BSDF) && any((SubstrateEnvLight.SpecularWeight + SubstrateEnvLight.SpecularHazeWeight) > 0.0f))
{
// SSR is traced for the sharpest lob. The smoothest one does not rely on SSR so we need to lower energy coming from SSR according to the lobe blend weight.
// And we also try to make the transition smooth using Haziness
Out.SSRReductionFactor -= dot(BSDFThroughput, float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f)) * SubstrateEnvLight.SSRReduction;
}
#endif
}
float4 ApplySSRContribution(FSSRContribution In, float4 InReflectionInput)
{
// Screen space reflections added on top of environment lighting.
// Alpha is 0 to not affect the subsurface diffuse luma information.
return float4(InReflectionInput.rgb * In.SSRTopLayerEnvBRDF * saturate(In.SSRReductionFactor), 0.0);
}
struct FLumenReflectionOnlyOutput
{
float4 LightingLobe0;
float4 LightingLobe1;
};
FLumenReflectionOnlyOutput GetLumenReflectionOnly(
in FSubstrateEnvLightResult SubstrateEnvLight,
in FSubstrateBSDF BSDF,
in float3 BSDFThroughput,
in float4 InReflectionInput)
{
FLumenReflectionOnlyOutput Out = (FLumenReflectionOnlyOutput)0;
Out.LightingLobe0.a = 1;
Out.LightingLobe1.a = 1;
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE
const bool bHasBackfaceDiffuse = SubstrateGetBSDFType(BSDF) == SUBSTRATE_BSDF_TYPE_SLAB && BSDF.HasBackScattering();
// Primary highlight
{
const float Roughness = SubstrateGetBSDFRoughness(BSDF);
const float FadeAlpha = LumenCombineReflectionsAlpha(Roughness, bHasBackfaceDiffuse);
// Must branch as Lumen Reflections can be uninitialized where not needed and contain NaN
if (FadeAlpha > 0.0f)
{
Out.LightingLobe0.rgb = InReflectionInput.xyz * FadeAlpha;
Out.LightingLobe0.a = 1 - FadeAlpha;
}
}
// Secondary highlight
#if SUBSTRATE_FASTPATH==0
if (any(SubstrateEnvLight.SpecularHazeWeight > 0.0f))
{
const float Roughness = SubstrateEnvLight.SpecularHazeSafeRoughness;
const float FadeAlpha = LumenCombineReflectionsAlpha(Roughness, bHasBackfaceDiffuse);
// Must branch as Lumen Reflections can be uninitialized where not needed and contain NaN
if (FadeAlpha > 0.0f)
{
Out.LightingLobe1.rgb = InReflectionInput.xyz * FadeAlpha;
Out.LightingLobe1.a = 1 - FadeAlpha;
}
}
#endif
#endif
return Out;
}
#endif // SUBTRATE_GBUFFER_FORMAT==1
void ReflectionEnvironmentSkyLighting(
in float4 SvPosition : SV_Position,
out float4 OutColor : SV_Target0
#if SUBSTRATE_OPAQUE_ROUGH_REFRACTION_ENABLED
, out float3 OutOpaqueRoughRefractionSceneColor : SV_Target1
, out float3 OutSubSurfaceSceneColor : SV_Target2
#endif
)
{
ResolvedView = ResolveView();
uint2 PixelPos = SvPosition.xy;
float2 BufferUV = SvPositionToBufferUV(SvPosition);
float2 ScreenPosition = SvPositionToScreenPosition(SvPosition).xy;
OutColor = 0.0f;
#if SUBSTRATE_OPAQUE_ROUGH_REFRACTION_ENABLED
OutOpaqueRoughRefractionSceneColor = 0.0f;
OutSubSurfaceSceneColor = 0.0f;
#endif
#if SUBTRATE_GBUFFER_FORMAT==1
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), Substrate.MaxBytesPerPixel);
FSubstratePixelHeader SubstratePixelHeader = UnpackSubstrateHeaderIn(Substrate.MaterialTextureArray, SubstrateAddressing, Substrate.TopLayerTexture);
BRANCH
if (SubstratePixelHeader.ClosureCount > 0) // This test is also enough to exclude sky pixels
{
float DeviceZ = SampleDeviceZFromSceneTextures(BufferUV);
float SceneDepth = ConvertFromDeviceZ(DeviceZ);
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), View.ScreenToTranslatedWorld).xyz;
float3 CameraToPixel = GetCameraVectorFromTranslatedWorldPosition(TranslatedWorldPosition);
float3 V = -CameraToPixel;
// Sample the ambient occlusion that is dynamically generated every frame.
float AmbientOcclusion = AmbientOcclusionTexture.SampleLevel(AmbientOcclusionSampler, BufferUV, 0).r;
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE
const float TopLayerSpecularContributionFactor = 1.0f;
#else
float4 SSRReflection = 0.0f.xxxx;
float TopLayerSpecularContributionFactor = 1.0f;
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_TILED_SSR
if (IsSSRTileUsed(PixelPos, SSRTiledViewRes, SSRTileMaskBuffer))
#endif
{
SSRReflection = Texture2DSample(ReflectionTexture, ReflectionTextureSampler, BufferUV);
// SSR is computed for the top level by averaging BSDF components.
// This is the top level specular contribution factor according to areas.
TopLayerSpecularContributionFactor = 1.0f - SSRReflection.a;
}
// A reduction of SSR contribution is needed when there is haziness because we only consider SSR for the sharpest lobe.
FSSRContribution SSRContribution = InitSSRContribution();
#endif
const float CloudVolumetricAOShadow = GetCloudVolumetricAOShadow(TranslatedWorldPosition);
const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(false /*bForceFullyRough*/, Substrate.bRoughDiffuse, Substrate.PeelLayersAboveDepth, Substrate.bRoughnessTracking);
FSubstrateDeferredLighting SubstrateLighting = GetInitialisedSubstrateDeferredLighting();
#if APPLY_SKY_SHADOWING
// Sample DFAO only once
const float2 BentNormalUV = (SvPosition.xy - View.ViewRectMin.xy) * View.BufferSizeAndInvSize.zw;
FUpsampleDFAOOutput UpsampleDFAOOutput = UpsampleDFAO(BentNormalUV, SceneDepth);
#endif
float CombinedScreenAndMaterialAO = SubstrateGetAO(SubstratePixelHeader) * AmbientOcclusion;
#if USE_DEFAULT_ENV_LIGHTING_INPUT && FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), SceneDepth, 0);
FCulledReflectionCapturesGridHeader CulledReflectionCapturesGridHeader = GetCulledReflectionCapturesGridHeader(GridIndex);
uint NumCulledReflectionCaptures = CulledReflectionCapturesGridHeader.NumReflectionCaptures;
uint CaptureDataStartIndex = CulledReflectionCapturesGridHeader.DataStartIndex;
#else
uint CaptureDataStartIndex = 0;
uint NumCulledReflectionCaptures = 0;
#endif
const bool bPixelMayHaveSSR = REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE || TopLayerSpecularContributionFactor < 1.0f;
const bool bEnableSpecular = ReflectionStruct.SkyLightParameters.y > 0.0f || NumCulledReflectionCaptures > 0 || bPixelMayHaveSSR;
Substrate_for (uint ClosureIndex = 0, ClosureIndex < SubstratePixelHeader.ClosureCount, ++ClosureIndex)
{
FSubstrateBSDF BSDF = UnpackSubstrateBSDF(Substrate.MaterialTextureArray, SubstrateAddressing, SubstratePixelHeader);
FSubstrateBSDFContext SubstrateBSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, BSDF, SubstrateAddressing, V);
const float3 BSDFThroughput = LuminanceWeight(SubstrateBSDFContext, BSDF); // Use the reflected direction
// Evaluate environment lighting
FSubstrateEnvLightResult SubstrateEnvLight = SubstrateEvaluateForEnvLight(SubstrateBSDFContext, bEnableSpecular, Settings);
float3 BentNormal = SubstrateEnvLight.DiffuseNormal;
#if APPLY_SKY_SHADOWING
// Set DiffuseNormal as the bent normal for all diffuse computations.
BentNormal = ApplyDFAO(UpsampleDFAOOutput, SubstrateEnvLight.DiffuseNormal);
#endif
float3 DiffuseLighting = 0;
float3 SpecularLighting = 0;
SubstrateEnvLightingCommon(
SubstrateEnvLight,
SubstratePixelHeader,
SubstrateBSDFContext,
BSDF,
BentNormal,
BSDFThroughput,
CaptureDataStartIndex,
NumCulledReflectionCaptures,
AmbientOcclusion,
CloudVolumetricAOShadow,
TopLayerSpecularContributionFactor,
TranslatedWorldPosition,
CombinedScreenAndMaterialAO,
DiffuseLighting,
SpecularLighting);
#if REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE
{
const FLumenReflectionOnlyOutput LumenReflections = GetLumenReflectionOnly(SubstrateEnvLight, BSDF, BSDFThroughput, Texture2DArraySample(LumenReflectionTexture, LumenReflectionTextureSampler, float3(BufferUV, ClosureIndex)));
SpecularLighting *= min(LumenReflections.LightingLobe0.a, LumenReflections.LightingLobe1.a);
// Primary specular lobe
{
SpecularLighting += LumenReflections.LightingLobe0.xyz * BSDFThroughput * SubstrateEnvLight.SpecularWeight;
}
// Secondary specular lobe
#if SUBSTRATE_FASTPATH==0
if (any(SubstrateEnvLight.SpecularHazeWeight > 0.0f))
{
SpecularLighting += LumenReflections.LightingLobe1.xyz * BSDFThroughput * SubstrateEnvLight.SpecularHazeWeight;
}
#endif
}
#else
if (BSDF_GETISTOPLAYER(BSDF))
{
GetSSSRContribution(SubstrateEnvLight, BSDF, BSDFThroughput, SSRContribution);
}
#endif
FLightAccumulator Out = (FLightAccumulator)0;
LightAccumulator_AddSplit(Out, DiffuseLighting, SpecularLighting, DiffuseLighting, 1.f /*CommonMultiplier*/, SubstrateEnvLight.bPostProcessSubsurface);
AccumulateSubstrateDeferredLighting(SubstrateLighting, Out, SubstrateEnvLight.bPostProcessSubsurface, BSDF_GETISTOPLAYER(BSDF));
}
OutColor = SubstrateLighting.SceneColor * (REFLECTION_SOURCE_TYPE == REFLECTION_SOURCE_LUMEN_STANDALONE ? 1.0f : View.PreExposure);
#if REFLECTION_SOURCE_TYPE != REFLECTION_SOURCE_LUMEN_STANDALONE
OutColor += ApplySSRContribution(SSRContribution, SSRReflection);
#endif
#if SUBSTRATE_OPAQUE_ROUGH_REFRACTION_ENABLED
OutOpaqueRoughRefractionSceneColor += SubstrateLighting.OpaqueRoughRefractionSceneColor;
OutSubSurfaceSceneColor += SubstrateLighting.SubSurfaceSceneColor;
OutOpaqueRoughRefractionSceneColor.rgb *= View.PreExposure;
OutSubSurfaceSceneColor.rgb *= View.PreExposure;
#endif
}
#else // SUBTRATE_GBUFFER_FORMAT==1
// Sample scene textures.
FGBufferData GBuffer = GetGBufferDataFromSceneTextures(BufferUV);
uint ShadingModelID = GBuffer.ShadingModelID;
const bool bUnlitMaterial = ShadingModelID == SHADINGMODELID_UNLIT;
float3 DiffuseColor = GBuffer.DiffuseColor;
float3 SpecularColor = GBuffer.SpecularColor;
RemapClearCoatDiffuseAndSpecularColor(GBuffer, ScreenPosition, DiffuseColor, SpecularColor);
// Sample the ambient occlusion that is dynamically generated every frame.
float AmbientOcclusion = AmbientOcclusionTexture.SampleLevel(AmbientOcclusionSampler, BufferUV, 0).r;
float3 BentNormal = GBuffer.WorldNormal;
#if APPLY_SKY_SHADOWING
{
const float2 BentNormalUV = (SvPosition.xy - View.ViewRectMin.xy) * View.BufferSizeAndInvSize.zw;
BentNormal = UpsampleDFAO(BentNormalUV, GBuffer.Depth, GBuffer.WorldNormal);
}
#endif
#if ENABLE_DYNAMIC_SKY_LIGHT
BRANCH
if (!bUnlitMaterial) // Only light pixels marked as lit
{
float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, GBuffer.Depth), GBuffer.Depth, 1), View.ScreenToTranslatedWorld).xyz;
const float CloudVolumetricAOShadow = GetCloudVolumetricAOShadow(TranslatedWorldPosition);
float3 SkyLighting = CloudVolumetricAOShadow * SkyLightDiffuse(GBuffer, AmbientOcclusion, BufferUV, ScreenPosition, BentNormal, DiffuseColor);
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(ShadingModelID);
LightAccumulator_Add(LightAccumulator, SkyLighting, SkyLighting, 1.0f, bNeedsSeparateSubsurfaceLightAccumulation);
OutColor = LightAccumulator_GetResult(LightAccumulator);
}
#endif // ENABLE_DYNAMIC_SKY_LIGHT
BRANCH
if (!bUnlitMaterial && ShadingModelID != SHADINGMODELID_HAIR)
{
OutColor.xyz += ReflectionEnvironment(GBuffer, AmbientOcclusion, BufferUV, ScreenPosition, SvPosition, BentNormal, SpecularColor, ShadingModelID);
}
#endif // SUBTRATE_GBUFFER_FORMAT==1
}