2486 lines
116 KiB
C++
2486 lines
116 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LumenSceneLighting.h"
|
|
#include "Materials/Material.h"
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "SceneUtils.h"
|
|
#include "PipelineStateCache.h"
|
|
#include "ShaderParameterStruct.h"
|
|
#include "ShaderPermutationUtils.h"
|
|
#include "VolumeLighting.h"
|
|
#include "DistanceFieldLightingShared.h"
|
|
#include "VolumetricCloudRendering.h"
|
|
#include "LumenTracingUtils.h"
|
|
#include "LightFunctionAtlas.h"
|
|
#include "LightFunctionRendering.h"
|
|
|
|
using namespace LightFunctionAtlas;
|
|
|
|
static TAutoConsoleVariable<int32> CVarLumenLumenSceneDirectLighting(
|
|
TEXT("r.LumenScene.DirectLighting"),
|
|
1,
|
|
TEXT("Whether to compute direct ligshting for surface cache."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
|
|
|
int32 GLumenDirectLightingOffscreenShadowingTraceMeshSDFs = 1;
|
|
FAutoConsoleVariableRef CVarLumenDirectLightingOffscreenShadowingTraceMeshSDFs(
|
|
TEXT("r.LumenScene.DirectLighting.OffscreenShadowing.TraceMeshSDFs"),
|
|
GLumenDirectLightingOffscreenShadowingTraceMeshSDFs,
|
|
TEXT("Whether to trace against Mesh Signed Distance Fields for offscreen shadowing, or to trace against the lower resolution Global SDF."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarLumenDirectLightingMaxLightsPerTile(
|
|
TEXT("r.LumenScene.DirectLighting.MaxLightsPerTile"),
|
|
8,
|
|
TEXT("Max number of lights to pick per tile based on their intenstiy and attenuation. Valid values are 4/8/16/32. Increasing this value will cause more memory usage and will slow down Lumen surface cache direct lighting pass."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarLumenDirectLightingCullToTileDepthRange(
|
|
TEXT("r.LumenScene.DirectLighting.CullToTileDepthRange"),
|
|
1,
|
|
TEXT("Whether to calculate each Card Tile's depth range and use it for tighter light culling."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GOffscreenShadowingTraceStepFactor = 5;
|
|
FAutoConsoleVariableRef CVarOffscreenShadowingTraceStepFactor(
|
|
TEXT("r.LumenScene.DirectLighting.OffscreenShadowingTraceStepFactor"),
|
|
GOffscreenShadowingTraceStepFactor,
|
|
TEXT(""),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GLumenDirectLightingCloudTransmittance = 1;
|
|
FAutoConsoleVariableRef CVarLumenDirectLightingCloudTransmittance(
|
|
TEXT("r.LumenScene.DirectLighting.CloudTransmittance"),
|
|
GLumenDirectLightingCloudTransmittance,
|
|
TEXT("Whether to sample cloud shadows when avaible."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarLumenDirectLightingMeshSDFShadowRayBias(
|
|
TEXT("r.LumenScene.DirectLighting.MeshSDF.ShadowRayBias"),
|
|
2.0f,
|
|
TEXT("Bias for tracing mesh SDF shadow rays."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarLumenDirectLightingHeightfieldShadowRayBias(
|
|
TEXT("r.LumenScene.DirectLighting.Heightfield.ShadowRayBias"),
|
|
2.0f,
|
|
TEXT("Bias for tracing heightfield shadow rays."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarLumenDirectLightingGlobalSDFShadowRayBias(
|
|
TEXT("r.LumenScene.DirectLighting.GlobalSDF.ShadowRayBias"),
|
|
1.0f,
|
|
TEXT("Bias for tracing global SDF shadow rays."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarLumenDirectLightingHardwareRayTracingShadowRayBias(
|
|
TEXT("r.LumenScene.DirectLighting.HardwareRayTracing.ShadowRayBias"),
|
|
1.0f,
|
|
TEXT("Bias for hardware ray tracing shadow rays."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarLumenDirectLightingHWRTAdaptiveShadowTracing(
|
|
TEXT("r.LumenScene.DirectLighting.HardwareRayTracing.AdaptiveShadowTracing"),
|
|
1,
|
|
TEXT("Whether to allow shooting fewer shadow rays for light tiles that were uniformly shadowed in the last lighting update."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarLumenDirectLightingBatchShadows(
|
|
TEXT("r.LumenScene.DirectLighting.BatchShadows"),
|
|
2,
|
|
TEXT("Whether to enable batching lumen light shadow passes. This cvar mainly exists for debugging."),
|
|
ECVF_RenderThreadSafe);
|
|
|
|
uint32 GetLumenLightingStatMode();
|
|
|
|
float LumenSceneDirectLighting::GetMeshSDFShadowRayBias()
|
|
{
|
|
return FMath::Max(CVarLumenDirectLightingMeshSDFShadowRayBias.GetValueOnRenderThread(), 0.0f);
|
|
}
|
|
|
|
float LumenSceneDirectLighting::GetHeightfieldShadowRayBias()
|
|
{
|
|
return FMath::Max(CVarLumenDirectLightingHeightfieldShadowRayBias.GetValueOnRenderThread(), 0.0f);
|
|
}
|
|
|
|
float LumenSceneDirectLighting::GetGlobalSDFShadowRayBias()
|
|
{
|
|
return FMath::Max(CVarLumenDirectLightingGlobalSDFShadowRayBias.GetValueOnRenderThread(), 0.0f);
|
|
}
|
|
|
|
float LumenSceneDirectLighting::GetHardwareRayTracingShadowRayBias()
|
|
{
|
|
return FMath::Max(CVarLumenDirectLightingHardwareRayTracingShadowRayBias.GetValueOnRenderThread(), 0.0f);
|
|
}
|
|
|
|
bool LumenSceneDirectLighting::UseLightTilesPerLightType()
|
|
{
|
|
return CVarLumenDirectLightingBatchShadows.GetValueOnRenderThread() == 2;
|
|
}
|
|
|
|
EPixelFormat Lumen::GetDirectLightingAtlasFormat()
|
|
{
|
|
return Lumen::GetLightingDataFormat();
|
|
}
|
|
|
|
EPixelFormat Lumen::GetIndirectLightingAtlasFormat()
|
|
{
|
|
return Lumen::GetLightingDataFormat();
|
|
}
|
|
|
|
class FLumenGatheredLight
|
|
{
|
|
public:
|
|
FLumenGatheredLight(
|
|
const FScene* Scene,
|
|
TConstArrayView<FViewInfo> Views,
|
|
const FLumenSceneFrameTemporaries& FrameTemporaries,
|
|
const FLightSceneInfo* InLightSceneInfo,
|
|
uint32 InLightIndex)
|
|
{
|
|
LightIndex = InLightIndex;
|
|
LightSceneInfo = InLightSceneInfo;
|
|
bHasShadows = InLightSceneInfo->Proxy->CastsDynamicShadow();
|
|
|
|
const FViewInfo& View = Views[0];
|
|
const FLightSceneProxy* Proxy = LightSceneInfo->Proxy;
|
|
|
|
Type = ELumenLightType::MAX;
|
|
const ELightComponentType LightType = (ELightComponentType)Proxy->GetLightType();
|
|
switch (LightType)
|
|
{
|
|
case LightType_Directional: Type = ELumenLightType::Directional; break;
|
|
case LightType_Point: Type = ELumenLightType::Point; break;
|
|
case LightType_Spot: Type = ELumenLightType::Spot; break;
|
|
case LightType_Rect: Type = ELumenLightType::Rect; break;
|
|
}
|
|
|
|
if (Type == ELumenLightType::Directional)
|
|
{
|
|
bMayCastCloudTransmittance = LightMayCastCloudShadow(Scene, View, LightSceneInfo);
|
|
}
|
|
|
|
LightFunctionMaterialProxy = Proxy->GetLightFunctionMaterial();
|
|
if (LightFunctionMaterialProxy && (!View.Family->EngineShowFlags.LightFunctions || !LightFunctionMaterialProxy->GetIncompleteMaterialWithFallback(Scene->GetFeatureLevel()).IsLightFunction()))
|
|
{
|
|
LightFunctionMaterialProxy = nullptr;
|
|
}
|
|
const bool bBatchableLightFunction = LightFunctionMaterialProxy == nullptr || (LightFunctionAtlas::IsEnabled(View, ELightFunctionAtlasSystem::Lumen) && LightSceneInfo->Proxy->HasValidLightFunctionAtlasSlot());
|
|
|
|
FSceneRenderer::GetLightNameForDrawEvent(Proxy, Name);
|
|
|
|
bNeedsShadowMask = bHasShadows || bMayCastCloudTransmittance || LightFunctionMaterialProxy;
|
|
|
|
// If evaluates to false, the light may still be eligible for batching during a raytraced shadow pass.
|
|
// The assumption is that such lights are not common so we are not optimizing for them.
|
|
bBatchedShadowsEligible = !bMayCastCloudTransmittance && bBatchableLightFunction && Type != ELumenLightType::Directional;
|
|
|
|
// Non-raytraced and distance field shadows require the light uniform buffer struct for each view but
|
|
// only for standalone lights if we do a single dispatch per light type.
|
|
if (NeedsShadowMask() && (!LumenSceneDirectLighting::UseLightTilesPerLightType() || !CanUseBatchedShadows()))
|
|
{
|
|
int32 NumViewOrigins = FrameTemporaries.ViewOrigins.Num();
|
|
DeferredLightUniformBuffers.SetNum(NumViewOrigins);
|
|
|
|
for (int32 OriginIndex = 0; OriginIndex < NumViewOrigins; ++OriginIndex)
|
|
{
|
|
FDeferredLightUniformStruct DeferredLightUniforms = GetDeferredLightParameters(*FrameTemporaries.ViewOrigins[OriginIndex].ReferenceView, *LightSceneInfo);
|
|
if (LightSceneInfo->Proxy->IsInverseSquared())
|
|
{
|
|
DeferredLightUniforms.LightParameters.FalloffExponent = 0;
|
|
}
|
|
DeferredLightUniforms.LightParameters.Color *= LightSceneInfo->Proxy->GetIndirectLightingScale();
|
|
DeferredLightUniformBuffers[OriginIndex] = CreateUniformBufferImmediate(DeferredLightUniforms, UniformBuffer_SingleFrame);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool NeedsShadowMask() const
|
|
{
|
|
return bNeedsShadowMask;
|
|
}
|
|
|
|
bool CanUseBatchedShadows() const
|
|
{
|
|
return bBatchedShadowsEligible;
|
|
}
|
|
|
|
const FLightSceneInfo* LightSceneInfo = nullptr;
|
|
const FMaterialRenderProxy* LightFunctionMaterialProxy = nullptr;
|
|
uint32 LightIndex = 0; // Index in the GatheredLights array
|
|
ELumenLightType Type = ELumenLightType::MAX;
|
|
bool bHasShadows = false;
|
|
bool bMayCastCloudTransmittance = false;
|
|
bool bNeedsShadowMask = false;
|
|
bool bBatchedShadowsEligible = false;
|
|
FString Name;
|
|
TArray<TUniformBufferRef<FDeferredLightUniformStruct>, TInlineAllocator<4>> DeferredLightUniformBuffers;
|
|
};
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FLumenLightTileScatterParameters, )
|
|
RDG_BUFFER_ACCESS(DrawIndirectArgs, ERHIAccess::IndirectArgs)
|
|
RDG_BUFFER_ACCESS(DispatchIndirectArgs, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint2>, LightTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileOffsetsPerLight)
|
|
SHADER_PARAMETER(int32, bUseLightTilesPerLightType)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FSpliceCardPagesIntoTilesCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FSpliceCardPagesIntoTilesCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FSpliceCardPagesIntoTilesCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(LumenSceneDirectLighting::FLightDataParameters, LumenLightData)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWCardTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWCardTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWLightTileAllocatorPerLight)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardPageIndexAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardPageIndexData)
|
|
SHADER_PARAMETER(uint32, MaxLightsPerTile)
|
|
SHADER_PARAMETER(uint32, NumLights)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
|
|
static int32 GetGroupSize()
|
|
{
|
|
return 8;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FSpliceCardPagesIntoTilesCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "SpliceCardPagesIntoTilesCS", SF_Compute);
|
|
|
|
class FInitializeCardTileIndirectArgsCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FInitializeCardTileIndirectArgsCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FInitializeCardTileIndirectArgsCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWDispatchCardTilesIndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTileAllocator)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static uint32 GetGroupSize()
|
|
{
|
|
return 64;
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FInitializeCardTileIndirectArgsCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "InitializeCardTileIndirectArgsCS", SF_Compute)
|
|
|
|
void Lumen::SpliceCardPagesIntoTiles(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FGlobalShaderMap* GlobalShaderMap,
|
|
const FLumenCardUpdateContext& CardUpdateContext,
|
|
const TRDGUniformBufferRef<FLumenCardScene>& LumenCardSceneUniformBuffer,
|
|
FLumenCardTileUpdateContext& OutCardTileUpdateContext,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
const uint32 MaxLightTilesTilesX = FMath::DivideAndRoundUp<uint32>(CardUpdateContext.UpdateAtlasSize.X, Lumen::CardTileSize);
|
|
const uint32 MaxLightTilesTilesY = FMath::DivideAndRoundUp<uint32>(CardUpdateContext.UpdateAtlasSize.Y, Lumen::CardTileSize);
|
|
const uint32 MaxLightTiles = MaxLightTilesTilesX * MaxLightTilesTilesY;
|
|
|
|
FRDGBufferRef CardTileAllocator = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), 1), TEXT("Lumen.CardTileAllocator"));
|
|
FRDGBufferRef CardTiles = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), MaxLightTiles), TEXT("Lumen.CardTiles"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(CardTileAllocator), 0, ComputePassFlags);
|
|
|
|
// Splice card pages into card tiles
|
|
{
|
|
FSpliceCardPagesIntoTilesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FSpliceCardPagesIntoTilesCS::FParameters>();
|
|
PassParameters->IndirectArgBuffer = CardUpdateContext.DispatchCardPageIndicesIndirectArgs;
|
|
PassParameters->LumenCardScene = LumenCardSceneUniformBuffer;
|
|
PassParameters->RWCardTileAllocator = GraphBuilder.CreateUAV(CardTileAllocator);
|
|
PassParameters->RWCardTiles = GraphBuilder.CreateUAV(CardTiles);
|
|
PassParameters->CardPageIndexAllocator = GraphBuilder.CreateSRV(CardUpdateContext.CardPageIndexAllocator);
|
|
PassParameters->CardPageIndexData = GraphBuilder.CreateSRV(CardUpdateContext.CardPageIndexData);
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FSpliceCardPagesIntoTilesCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("SpliceCardPagesIntoTiles"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
CardUpdateContext.DispatchCardPageIndicesIndirectArgs,
|
|
FLumenCardUpdateContext::EIndirectArgOffset::ThreadPerTile);
|
|
}
|
|
|
|
// Setup indirect args for card tile processing
|
|
FRDGBufferRef DispatchCardTilesIndirectArgs = GraphBuilder.CreateBuffer(
|
|
FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>((uint32)ELumenDispatchCardTilesIndirectArgsOffset::Num),
|
|
TEXT("Lumen.DispatchCardTilesIndirectArgs"));
|
|
{
|
|
FInitializeCardTileIndirectArgsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FInitializeCardTileIndirectArgsCS::FParameters>();
|
|
PassParameters->RWDispatchCardTilesIndirectArgs = GraphBuilder.CreateUAV(DispatchCardTilesIndirectArgs);
|
|
PassParameters->CardTileAllocator = GraphBuilder.CreateSRV(CardTileAllocator);
|
|
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FInitializeCardTileIndirectArgsCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("InitializeCardTileIndirectArgs"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(1, 1, 1));
|
|
}
|
|
|
|
OutCardTileUpdateContext.CardTileAllocator = CardTileAllocator;
|
|
OutCardTileUpdateContext.CardTiles = CardTiles;
|
|
OutCardTileUpdateContext.DispatchCardTilesIndirectArgs = DispatchCardTilesIndirectArgs;
|
|
}
|
|
|
|
class FCalculateCardTileDepthRangesCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FCalculateCardTileDepthRangesCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FCalculateCardTileDepthRangesCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWCardTileDepthRanges)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTiles)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
using FPermutationDomain = TShaderPermutationDomain<>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
|
|
static int32 GetGroupSize()
|
|
{
|
|
return Lumen::CardTileSize;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FCalculateCardTileDepthRangesCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "CalculateCardTileDepthRangesCS", SF_Compute);
|
|
|
|
class FBuildLightTilesCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FBuildLightTilesCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FBuildLightTilesCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(LumenSceneDirectLighting::FLightDataParameters, LumenLightData)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWLightTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWLightTileAllocatorForPerCardTileDispatch)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint2>, RWLightTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWLightTileAllocatorPerLight)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWLightTileOffsetNumPerCardTile)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTileDepthRanges)
|
|
SHADER_PARAMETER(uint32, CullToCardTileDepthRange)
|
|
SHADER_PARAMETER(uint32, MaxLightsPerTile)
|
|
SHADER_PARAMETER(uint32, NumLights)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
SHADER_PARAMETER_ARRAY(FMatrix44f, FrustumTranslatedWorldToClip, [LUMEN_MAX_VIEWS])
|
|
SHADER_PARAMETER_ARRAY(FVector4f, PreViewTranslationHigh, [LUMEN_MAX_VIEWS])
|
|
SHADER_PARAMETER_ARRAY(FVector4f, PreViewTranslationLow, [LUMEN_MAX_VIEWS])
|
|
SHADER_PARAMETER(FVector2f, ViewExposure)
|
|
SHADER_PARAMETER(int32, bUseLightTilesPerLightType)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FMaxLightSamples : SHADER_PERMUTATION_SPARSE_INT("MAX_LIGHT_SAMPLES", 1, 2, 4, 8, 16, 32);
|
|
using FPermutationDomain = TShaderPermutationDomain<FMaxLightSamples>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
|
|
}
|
|
|
|
static int32 GetGroupSize()
|
|
{
|
|
return 64;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FBuildLightTilesCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "BuildLightTilesCS", SF_Compute);
|
|
|
|
class FComputeLightTileOffsetsPerLightCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FComputeLightTileOffsetsPerLightCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FComputeLightTileOffsetsPerLightCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWLightTileOffsetsPerLight)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileAllocatorPerLight)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<int>, StandaloneLightIndices)
|
|
SHADER_PARAMETER(uint32, NumLights)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
SHADER_PARAMETER(uint32, NumStandaloneLights)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FUseStandaloneLightIndices : SHADER_PERMUTATION_BOOL("USE_STANDALONE_LIGHT_INDICES");
|
|
using FPermutationDomain = TShaderPermutationDomain<FUseStandaloneLightIndices>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static uint32 GetGroupSize()
|
|
{
|
|
return 64;
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FComputeLightTileOffsetsPerLightCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "ComputeLightTileOffsetsPerLightCS", SF_Compute);
|
|
|
|
class FCompactLightTilesCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FCompactLightTilesCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FCompactLightTilesCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint2>, RWCompactedLightTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint2>, RWLightTilesPerCardTile)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWCompactedLightTileAllocatorPerLight)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint2>, LightTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileOffsetsPerLight)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileOffsetNumPerCardTile)
|
|
SHADER_PARAMETER(uint32, NumLights)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
SHADER_PARAMETER(int32, bUseLightTilesPerLightType)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
|
|
static int32 GetGroupSize()
|
|
{
|
|
return 64;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FCompactLightTilesCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "CompactLightTilesCS", SF_Compute);
|
|
|
|
class FInitializeLightTileIndirectArgsCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FInitializeLightTileIndirectArgsCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FInitializeLightTileIndirectArgsCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWDispatchLightTilesIndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWDrawTilesPerLightIndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWDispatchTilesPerLightIndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileAllocatorPerLight)
|
|
SHADER_PARAMETER(uint32, VertexCountPerInstanceIndirect)
|
|
SHADER_PARAMETER(uint32, PerLightDispatchFactor)
|
|
SHADER_PARAMETER(uint32, NumLights)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static uint32 GetGroupSize()
|
|
{
|
|
return 64;
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FInitializeLightTileIndirectArgsCS, "/Engine/Private/Lumen/LumenSceneDirectLightingCulling.usf", "InitializeLightTileIndirectArgsCS", SF_Compute)
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FClearLumenCardsParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FRasterizeToCardsVS::FParameters, VS)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FClearLumenCardsPS::FParameters, PS)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
void ClearLumenSceneDirectLighting(
|
|
const FViewInfo& View,
|
|
FRDGBuilder& GraphBuilder,
|
|
const FLumenSceneData& LumenSceneData,
|
|
const FLumenSceneFrameTemporaries& FrameTemporaries,
|
|
FLumenCardUpdateContext CardUpdateContext)
|
|
{
|
|
FClearLumenCardsParameters* PassParameters = GraphBuilder.AllocParameters<FClearLumenCardsParameters>();
|
|
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(FrameTemporaries.DirectLightingAtlas, ERenderTargetLoadAction::ELoad);
|
|
PassParameters->VS.LumenCardScene = FrameTemporaries.LumenCardSceneUniformBuffer;
|
|
PassParameters->VS.DrawIndirectArgs = CardUpdateContext.DrawCardPageIndicesIndirectArgs;
|
|
PassParameters->VS.CardPageIndexAllocator = GraphBuilder.CreateSRV(CardUpdateContext.CardPageIndexAllocator);
|
|
PassParameters->VS.CardPageIndexData = GraphBuilder.CreateSRV(CardUpdateContext.CardPageIndexData);
|
|
PassParameters->VS.IndirectLightingAtlasSize = LumenSceneData.GetRadiosityAtlasSize();
|
|
PassParameters->PS.View = View.ViewUniformBuffer;
|
|
PassParameters->PS.LumenCardScene = FrameTemporaries.LumenCardSceneUniformBuffer;
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("ClearDirectLighting"),
|
|
PassParameters,
|
|
ERDGPassFlags::Raster,
|
|
[ViewportSize = LumenSceneData.GetPhysicalAtlasSize(), PassParameters, GlobalShaderMap = View.ShaderMap](FRDGAsyncTask, FRHICommandList& RHICmdList)
|
|
{
|
|
FClearLumenCardsPS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FClearLumenCardsPS::FNumTargets>(1);
|
|
auto PixelShader = GlobalShaderMap->GetShader<FClearLumenCardsPS>(PermutationVector);
|
|
|
|
auto VertexShader = GlobalShaderMap->GetShader<FRasterizeToCardsVS>();
|
|
|
|
DrawQuadsToAtlas(
|
|
ViewportSize,
|
|
VertexShader,
|
|
PixelShader,
|
|
PassParameters,
|
|
GlobalShaderMap,
|
|
TStaticBlendState<>::GetRHI(),
|
|
RHICmdList,
|
|
[](FRHICommandList& RHICmdList, TShaderRefBase<FClearLumenCardsPS, FShaderMapPointerTable> Shader, FRHIPixelShader* ShaderRHI, const typename FClearLumenCardsPS::FParameters& Parameters) {},
|
|
PassParameters->VS.DrawIndirectArgs,
|
|
0);
|
|
});
|
|
}
|
|
|
|
class FLumenCardBatchDirectLightingCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FLumenCardBatchDirectLightingCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FLumenCardBatchDirectLightingCS, FGlobalShader)
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
// This shader isn't view specific but the RectLightAtlasTexture, though doesn't vary per view, is accessed through the view uniform buffer
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(LumenSceneDirectLighting::FLightDataParameters, LumenLightData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, ShadowMaskTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightTileOffsetNumPerCardTile)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint2>, LightTilesPerCardTile)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float3>, RWDirectLightingAtlas)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint4>, RWTileShadowDownsampleFactorAtlas)
|
|
SHADER_PARAMETER_ARRAY(FVector4f, PreViewTranslationHigh, [LUMEN_MAX_VIEWS])
|
|
SHADER_PARAMETER_ARRAY(FVector4f, PreViewTranslationLow, [LUMEN_MAX_VIEWS])
|
|
SHADER_PARAMETER(FVector2f, ViewExposure)
|
|
SHADER_PARAMETER(FVector3f, TargetFormatQuantizationError)
|
|
SHADER_PARAMETER(float, CachedLightingPreExposure)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FMultiView : SHADER_PERMUTATION_BOOL("HAS_MULTIPLE_VIEWS");
|
|
class FHasRectLights : SHADER_PERMUTATION_BOOL("HAS_RECT_LIGHTS");
|
|
class FWaveOpWaveSize : SHADER_PERMUTATION_SPARSE_INT("WAVE_OP_WAVE_SIZE", 0, 64); // TODO: wave32 support
|
|
using FPermutationDomain = TShaderPermutationDomain<FMultiView, FHasRectLights, FWaveOpWaveSize>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (!UE::ShaderPermutationUtils::ShouldCompileWithWaveSize(Parameters, PermutationVector.Get<FWaveOpWaveSize>()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (!UE::ShaderPermutationUtils::ShouldPrecacheWithWaveSize(Parameters, PermutationVector.Get<FWaveOpWaveSize>()))
|
|
{
|
|
return EShaderPermutationPrecacheRequest::NotUsed;
|
|
}
|
|
|
|
return FGlobalShader::ShouldPrecachePermutation(Parameters);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("USE_LIGHT_UNIFORM_BUFFER"), 0);
|
|
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (PermutationVector.Get<FWaveOpWaveSize>() > 0)
|
|
{
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
|
|
}
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FLumenCardBatchDirectLightingCS, "/Engine/Private/Lumen/LumenSceneDirectLighting.usf", "LumenCardBatchDirectLightingCS", SF_Compute);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FPerLightParameters, )
|
|
SHADER_PARAMETER(uint32, LightIndex)
|
|
SHADER_PARAMETER(float, TanLightSourceAngle)
|
|
SHADER_PARAMETER_STRUCT_REF(FDeferredLightUniformStruct, DeferredLightUniforms)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FLumenDirectLightingNonRayTracedShadowsParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWShadowMaskTiles)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWShadowTraceAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWShadowTraces)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, TileShadowDownsampleFactorAtlas)
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FPerLightParameters, LightParameters)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLumenLightTileScatterParameters, LightTileScatterParameters)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(LumenSceneDirectLighting::FLightDataParameters, LumenLightData)
|
|
SHADER_PARAMETER(uint32, CardScatterInstanceIndex)
|
|
SHADER_PARAMETER(uint32, ViewIndex)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
SHADER_PARAMETER(uint32, DummyZeroForFixingShaderCompilerBug)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FForwardLightUniformParameters, ForwardLightStruct)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLightCloudTransmittanceParameters, LightCloudTransmittanceParameters)
|
|
SHADER_PARAMETER(float, HeightfieldShadowReceiverBias)
|
|
SHADER_PARAMETER(float, StepFactor)
|
|
SHADER_PARAMETER(float, MaxTraceDistance)
|
|
SHADER_PARAMETER(int32, bAdaptiveShadowTracing)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FLumenDirectLightingShadowMaskFromLightAttenuationCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FLumenDirectLightingShadowMaskFromLightAttenuationCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FLumenDirectLightingShadowMaskFromLightAttenuationCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLumenDirectLightingNonRayTracedShadowsParameters, Common)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLightFunctionAtlasGlobalParameters, LightFunctionAtlas)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FThreadGroupSize32 : SHADER_PERMUTATION_BOOL("THREADGROUP_SIZE_32");
|
|
class FCompactShadowTraces : SHADER_PERMUTATION_BOOL("COMPACT_SHADOW_TRACES");
|
|
class FLightType : SHADER_PERMUTATION_ENUM_CLASS("LIGHT_TYPE", ELumenLightType);
|
|
class FCloudTransmittance : SHADER_PERMUTATION_BOOL("USE_CLOUD_TRANSMITTANCE");
|
|
class FLightFunctionAtlas : SHADER_PERMUTATION_BOOL("USE_LIGHT_FUNCTION_ATLAS");
|
|
using FPermutationDomain = TShaderPermutationDomain<FThreadGroupSize32, FCompactShadowTraces, FLightType, FCloudTransmittance, FLightFunctionAtlas>;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (PermutationVector.Get<FCloudTransmittance>() && PermutationVector.Get<FLightType>() != ELumenLightType::Directional)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
|
|
OutEnvironment.SetDefine(TEXT("LIGHT_FUNCTION"), 0);
|
|
OutEnvironment.SetDefine(TEXT("USE_IES_PROFILE"), 1);
|
|
OutEnvironment.SetDefine(TEXT("SUBSTRATE_INLINE_SHADING"), 1);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FLumenDirectLightingShadowMaskFromLightAttenuationCS, "/Engine/Private/Lumen/LumenSceneDirectLightingShadowMask.usf", "LumenSceneDirectLightingShadowMaskFromLightAttenuationCS", SF_Compute);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FLightFunctionParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FPrimitiveUniformShaderParameters, PrimitiveUniformBuffer)
|
|
SHADER_PARAMETER(FVector4f, LightFunctionParameters)
|
|
SHADER_PARAMETER(FMatrix44f, LightFunctionTranslatedWorldToLight)
|
|
SHADER_PARAMETER(FVector3f, LightFunctionParameters2)
|
|
SHADER_PARAMETER(FVector3f, CameraRelativeLightPosition)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS : public FMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS, Material);
|
|
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FMaterialShader(Initializer)
|
|
{
|
|
Bindings.BindForLegacyShaderParameters(
|
|
this,
|
|
Initializer.PermutationId,
|
|
Initializer.ParameterMap,
|
|
*FParameters::FTypeInfo::GetStructMetadata(),
|
|
// Don't require full bindings, we use FMaterialShader::SetParameters
|
|
false);
|
|
}
|
|
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS() {}
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLumenDirectLightingNonRayTracedShadowsParameters, Common)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLightFunctionParameters, LightFunctionParameters)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FThreadGroupSize32 : SHADER_PERMUTATION_BOOL("THREADGROUP_SIZE_32");
|
|
class FCompactShadowTraces : SHADER_PERMUTATION_BOOL("COMPACT_SHADOW_TRACES");
|
|
class FLightType : SHADER_PERMUTATION_ENUM_CLASS("LIGHT_TYPE", ELumenLightType);
|
|
class FCloudTransmittance : SHADER_PERMUTATION_BOOL("USE_CLOUD_TRANSMITTANCE");
|
|
using FPermutationDomain = TShaderPermutationDomain<FThreadGroupSize32, FCompactShadowTraces, FLightType, FCloudTransmittance>;
|
|
|
|
static bool ShouldCompilePermutation(const FMaterialShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (PermutationVector.Get<FCloudTransmittance>() && PermutationVector.Get<FLightType>() != ELumenLightType::Directional)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Parameters.MaterialParameters.MaterialDomain == EMaterialDomain::MD_LightFunction && DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FMaterialShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
|
|
OutEnvironment.SetDefine(TEXT("LIGHT_FUNCTION"), 1);
|
|
OutEnvironment.SetDefine(TEXT("USE_IES_PROFILE"), 1);
|
|
OutEnvironment.SetDefine(TEXT("SUBSTRATE_INLINE_SHADING"), 1);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(, FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS, TEXT("/Engine/Private/Lumen/LumenSceneDirectLightingShadowMask.usf"), TEXT("LumenSceneDirectLightingShadowMaskFromLightAttenuationCS"), SF_Compute);
|
|
|
|
class FInitShadowTraceIndirectArgsCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FInitShadowTraceIndirectArgsCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FInitShadowTraceIndirectArgsCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWShadowTraceIndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, ShadowTraceAllocator)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static uint32 GetGroupSize()
|
|
{
|
|
return 64;
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FInitShadowTraceIndirectArgsCS, "/Engine/Private/Lumen/LumenSceneDirectLightingSoftwareRayTracing.usf", "InitShadowTraceIndirectArgsCS", SF_Compute)
|
|
|
|
class FLumenSceneDirectLightingTraceDistanceFieldShadowsCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FLumenSceneDirectLightingTraceDistanceFieldShadowsCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FLumenSceneDirectLightingTraceDistanceFieldShadowsCS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
RDG_BUFFER_ACCESS(IndirectArgBuffer, ERHIAccess::IndirectArgs)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWShadowMaskTiles)
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FPerLightParameters, LightParameters)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLumenLightTileScatterParameters, LightTileScatterParameters)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(LumenSceneDirectLighting::FLightDataParameters, LumenLightData)
|
|
SHADER_PARAMETER(uint32, ViewIndex)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
SHADER_PARAMETER(uint32, DummyZeroForFixingShaderCompilerBug)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldObjectBufferParameters, ObjectBufferParameters)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FLightTileIntersectionParameters, LightTileIntersectionParameters)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FDistanceFieldAtlasParameters, DistanceFieldAtlasParameters)
|
|
SHADER_PARAMETER(FMatrix44f, TranslatedWorldToShadow)
|
|
SHADER_PARAMETER(float, TwoSidedMeshDistanceBiasScale)
|
|
SHADER_PARAMETER(float, StepFactor)
|
|
SHADER_PARAMETER(float, MaxTraceDistance)
|
|
SHADER_PARAMETER(float, MeshSDFShadowRayBias)
|
|
SHADER_PARAMETER(float, HeightfieldShadowRayBias)
|
|
SHADER_PARAMETER(float, GlobalSDFShadowRayBias)
|
|
SHADER_PARAMETER(int32, HeightfieldMaxTracingSteps)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class FThreadGroupSize32 : SHADER_PERMUTATION_BOOL("THREADGROUP_SIZE_32");
|
|
class FLightType : SHADER_PERMUTATION_ENUM_CLASS("LIGHT_TYPE", ELumenLightType);
|
|
class FTraceGlobalSDF : SHADER_PERMUTATION_BOOL("OFFSCREEN_SHADOWING_TRACE_GLOBAL_SDF");
|
|
class FSimpleCoverageBasedExpand : SHADER_PERMUTATION_BOOL("GLOBALSDF_SIMPLE_COVERAGE_BASED_EXPAND");
|
|
class FTraceMeshSDFs : SHADER_PERMUTATION_BOOL("OFFSCREEN_SHADOWING_TRACE_MESH_SDF");
|
|
class FTraceHeightfields : SHADER_PERMUTATION_BOOL("OFFSCREEN_SHADOWING_TRACE_HEIGHTFIELDS");
|
|
class FOffsetDataStructure : SHADER_PERMUTATION_INT("OFFSET_DATA_STRUCT", 3);
|
|
using FPermutationDomain = TShaderPermutationDomain<FThreadGroupSize32, FLightType, FTraceGlobalSDF, FSimpleCoverageBasedExpand, FTraceMeshSDFs, FTraceHeightfields, FOffsetDataStructure>;
|
|
|
|
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
|
|
{
|
|
// Only directional lights support mesh SDF offscreen shadowing
|
|
if (PermutationVector.Get<FLightType>() != ELumenLightType::Directional)
|
|
{
|
|
PermutationVector.Set<FTraceMeshSDFs>(false);
|
|
PermutationVector.Set<FTraceHeightfields>(false);
|
|
}
|
|
|
|
// Don't trace global SDF if per mesh object traces are enabled
|
|
if (PermutationVector.Get<FTraceMeshSDFs>() || PermutationVector.Get<FTraceHeightfields>())
|
|
{
|
|
PermutationVector.Set<FTraceGlobalSDF>(false);
|
|
}
|
|
|
|
// FOffsetDataStructure is only used for mesh SDFs
|
|
if (!PermutationVector.Get<FTraceMeshSDFs>())
|
|
{
|
|
PermutationVector.Set<FOffsetDataStructure>(0);
|
|
}
|
|
|
|
if (!PermutationVector.Get<FTraceGlobalSDF>())
|
|
{
|
|
PermutationVector.Set<FSimpleCoverageBasedExpand>(false);
|
|
}
|
|
|
|
return PermutationVector;
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (RemapPermutation(PermutationVector) != PermutationVector)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
FORCENOINLINE static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FLumenSceneDirectLightingTraceDistanceFieldShadowsCS, "/Engine/Private/Lumen/LumenSceneDirectLightingSoftwareRayTracing.usf", "LumenSceneDirectLightingTraceDistanceFieldShadowsCS", SF_Compute);
|
|
|
|
void SetupLightFunctionParameters(const FViewInfo& View, const FLightSceneInfo* LightSceneInfo, float ShadowFadeFraction, FLightFunctionParameters& OutParameters)
|
|
{
|
|
const bool bIsSpotLight = LightSceneInfo->Proxy->GetLightType() == LightType_Spot;
|
|
const bool bIsPointLight = LightSceneInfo->Proxy->GetLightType() == LightType_Point;
|
|
const float TanOuterAngle = bIsSpotLight ? FMath::Tan(LightSceneInfo->Proxy->GetOuterConeAngle()) : 1.0f;
|
|
|
|
OutParameters.LightFunctionParameters = FVector4f(TanOuterAngle, ShadowFadeFraction, bIsSpotLight ? 1.0f : 0.0f, bIsPointLight ? 1.0f : 0.0f);
|
|
|
|
const FVector Scale = LightSceneInfo->Proxy->GetLightFunctionScale();
|
|
// Switch x and z so that z of the user specified scale affects the distance along the light direction
|
|
const FVector InverseScale = FVector( 1.f / Scale.Z, 1.f / Scale.Y, 1.f / Scale.X );
|
|
const FMatrix WorldToLight = LightSceneInfo->Proxy->GetWorldToLight() * FScaleMatrix(FVector(InverseScale));
|
|
|
|
OutParameters.LightFunctionTranslatedWorldToLight = FMatrix44f(FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation()) * WorldToLight);
|
|
|
|
const float PreviewShadowsMask = 0.0f;
|
|
OutParameters.LightFunctionParameters2 = FVector3f(
|
|
LightSceneInfo->Proxy->GetLightFunctionFadeDistance(),
|
|
LightSceneInfo->Proxy->GetLightFunctionDisabledBrightness(),
|
|
PreviewShadowsMask);
|
|
|
|
OutParameters.CameraRelativeLightPosition = GetCamRelativeLightPosition(View.ViewMatrices, *LightSceneInfo);
|
|
|
|
OutParameters.PrimitiveUniformBuffer = GIdentityPrimitiveUniformBuffer.GetUniformBufferRef();
|
|
}
|
|
|
|
void SetupMeshSDFShadowInitializer(
|
|
const FLightSceneInfo* LightSceneInfo,
|
|
const FBox& LumenSceneBounds,
|
|
FSphere& OutShadowBounds,
|
|
FWholeSceneProjectedShadowInitializer& OutInitializer)
|
|
{
|
|
FSphere Bounds;
|
|
|
|
{
|
|
// Get the 8 corners of the cascade's camera frustum, in world space
|
|
FVector CascadeFrustumVerts[8];
|
|
const FVector LumenSceneCenter = LumenSceneBounds.GetCenter();
|
|
const FVector LumenSceneExtent = LumenSceneBounds.GetExtent();
|
|
CascadeFrustumVerts[0] = LumenSceneCenter + FVector(LumenSceneExtent.X, LumenSceneExtent.Y, LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[1] = LumenSceneCenter + FVector(LumenSceneExtent.X, LumenSceneExtent.Y, -LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[2] = LumenSceneCenter + FVector(LumenSceneExtent.X, -LumenSceneExtent.Y, LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[3] = LumenSceneCenter + FVector(LumenSceneExtent.X, -LumenSceneExtent.Y, -LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[4] = LumenSceneCenter + FVector(-LumenSceneExtent.X, LumenSceneExtent.Y, LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[5] = LumenSceneCenter + FVector(-LumenSceneExtent.X, LumenSceneExtent.Y, -LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[6] = LumenSceneCenter + FVector(-LumenSceneExtent.X, -LumenSceneExtent.Y, LumenSceneExtent.Z);
|
|
CascadeFrustumVerts[7] = LumenSceneCenter + FVector(-LumenSceneExtent.X, -LumenSceneExtent.Y, -LumenSceneExtent.Z);
|
|
|
|
Bounds = FSphere(LumenSceneCenter, 0);
|
|
for (int32 Index = 0; Index < 8; Index++)
|
|
{
|
|
Bounds.W = FMath::Max(Bounds.W, FVector::DistSquared(CascadeFrustumVerts[Index], Bounds.Center));
|
|
}
|
|
|
|
Bounds.W = FMath::Max(FMath::Sqrt(Bounds.W), 1.0f);
|
|
|
|
ComputeShadowCullingVolume(true, CascadeFrustumVerts, -LightSceneInfo->Proxy->GetDirection(), OutInitializer.CascadeSettings.ShadowBoundsAccurate, OutInitializer.CascadeSettings.NearFrustumPlane, OutInitializer.CascadeSettings.FarFrustumPlane);
|
|
}
|
|
|
|
OutInitializer.CascadeSettings.ShadowSplitIndex = 0;
|
|
|
|
const float ShadowExtent = Bounds.W / FMath::Sqrt(3.0f);
|
|
const FBoxSphereBounds SubjectBounds(Bounds.Center, FVector(ShadowExtent, ShadowExtent, ShadowExtent), Bounds.W);
|
|
OutInitializer.PreShadowTranslation = -Bounds.Center;
|
|
OutInitializer.WorldToLight = FInverseRotationMatrix(LightSceneInfo->Proxy->GetDirection().GetSafeNormal().Rotation());
|
|
OutInitializer.Scales = FVector2D(1.0f / Bounds.W, 1.0f / Bounds.W);
|
|
OutInitializer.SubjectBounds = FBoxSphereBounds(FVector::ZeroVector, SubjectBounds.BoxExtent, SubjectBounds.SphereRadius);
|
|
OutInitializer.WAxis = FVector4(0, 0, 0, 1);
|
|
OutInitializer.MinLightW = FMath::Min<float>(-0.5f * UE_OLD_WORLD_MAX, -SubjectBounds.SphereRadius);
|
|
const float MaxLightW = SubjectBounds.SphereRadius;
|
|
OutInitializer.MaxDistanceToCastInLightW = MaxLightW - OutInitializer.MinLightW;
|
|
OutInitializer.bRayTracedDistanceField = true;
|
|
OutInitializer.CascadeSettings.bFarShadowCascade = false;
|
|
|
|
const float SplitNear = -Bounds.W;
|
|
const float SplitFar = Bounds.W;
|
|
|
|
OutInitializer.CascadeSettings.SplitFarFadeRegion = 0.0f;
|
|
OutInitializer.CascadeSettings.SplitNearFadeRegion = 0.0f;
|
|
OutInitializer.CascadeSettings.SplitFar = SplitFar;
|
|
OutInitializer.CascadeSettings.SplitNear = SplitNear;
|
|
OutInitializer.CascadeSettings.FadePlaneOffset = SplitFar;
|
|
OutInitializer.CascadeSettings.FadePlaneLength = 0;
|
|
OutInitializer.CascadeSettings.CascadeBiasDistribution = 0;
|
|
OutInitializer.CascadeSettings.ShadowSplitIndex = 0;
|
|
|
|
OutShadowBounds = Bounds;
|
|
}
|
|
|
|
void CullMeshObjectsForLightCards(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FScene* Scene,
|
|
const FViewInfo& View,
|
|
const FLightSceneInfo* LightSceneInfo,
|
|
EDistanceFieldPrimitiveType PrimitiveType,
|
|
const FDistanceFieldObjectBufferParameters& ObjectBufferParameters,
|
|
FMatrix& WorldToMeshSDFShadowValue,
|
|
FLightTileIntersectionParameters& LightTileIntersectionParameters)
|
|
{
|
|
const FVector LumenSceneViewOrigin = Lumen::GetLumenSceneViewOrigin(View, Lumen::GetNumGlobalDFClipmaps(View) - 1);
|
|
const FVector LumenSceneExtent = FVector(LumenScene::GetCardMaxDistance(View));
|
|
const FBox LumenSceneBounds(LumenSceneViewOrigin - LumenSceneExtent, LumenSceneViewOrigin + LumenSceneExtent);
|
|
|
|
FSphere MeshSDFShadowBounds;
|
|
FWholeSceneProjectedShadowInitializer MeshSDFShadowInitializer;
|
|
SetupMeshSDFShadowInitializer(LightSceneInfo, LumenSceneBounds, MeshSDFShadowBounds, MeshSDFShadowInitializer);
|
|
|
|
const FMatrix FaceMatrix(
|
|
FPlane(0, 0, 1, 0),
|
|
FPlane(0, 1, 0, 0),
|
|
FPlane(-1, 0, 0, 0),
|
|
FPlane(0, 0, 0, 1));
|
|
|
|
const FMatrix TranslatedWorldToView = MeshSDFShadowInitializer.WorldToLight * FaceMatrix;
|
|
|
|
double MaxSubjectZ = TranslatedWorldToView.TransformPosition(MeshSDFShadowInitializer.SubjectBounds.Origin).Z + MeshSDFShadowInitializer.SubjectBounds.SphereRadius;
|
|
MaxSubjectZ = FMath::Min(MaxSubjectZ, MeshSDFShadowInitializer.MaxDistanceToCastInLightW);
|
|
const double MinSubjectZ = FMath::Max(MaxSubjectZ - MeshSDFShadowInitializer.SubjectBounds.SphereRadius * 2, MeshSDFShadowInitializer.MinLightW);
|
|
|
|
const FMatrix ScaleMatrix = FScaleMatrix( FVector( MeshSDFShadowInitializer.Scales.X, MeshSDFShadowInitializer.Scales.Y, 1.0f ) );
|
|
const FMatrix ViewToClip = ScaleMatrix * FShadowProjectionMatrix(MinSubjectZ, MaxSubjectZ, MeshSDFShadowInitializer.WAxis);
|
|
const FMatrix SubjectAndReceiverMatrix = TranslatedWorldToView * ViewToClip;
|
|
|
|
int32 NumPlanes = MeshSDFShadowInitializer.CascadeSettings.ShadowBoundsAccurate.Planes.Num();
|
|
const FPlane* PlaneData = MeshSDFShadowInitializer.CascadeSettings.ShadowBoundsAccurate.Planes.GetData();
|
|
FVector PrePlaneTranslation = FVector::ZeroVector;
|
|
FVector4f LocalLightShadowBoundingSphere = FVector4f::Zero();
|
|
|
|
WorldToMeshSDFShadowValue = FTranslationMatrix(MeshSDFShadowInitializer.PreShadowTranslation) * SubjectAndReceiverMatrix;
|
|
|
|
FDistanceFieldCulledObjectBufferParameters CulledObjectBufferParameters;
|
|
|
|
const bool bCullingForDirectShadowing = false;
|
|
const bool bCullHeighfieldsNotInAtlas = false;
|
|
|
|
CullDistanceFieldObjectsForLight(
|
|
GraphBuilder,
|
|
View,
|
|
LightSceneInfo->Proxy,
|
|
PrimitiveType,
|
|
WorldToMeshSDFShadowValue,
|
|
NumPlanes,
|
|
PlaneData,
|
|
PrePlaneTranslation,
|
|
LocalLightShadowBoundingSphere,
|
|
MeshSDFShadowBounds.W,
|
|
bCullingForDirectShadowing,
|
|
bCullHeighfieldsNotInAtlas,
|
|
ObjectBufferParameters,
|
|
CulledObjectBufferParameters,
|
|
LightTileIntersectionParameters);
|
|
}
|
|
|
|
static void RenderDirectLightIntoLumenCardsBatched(
|
|
FRDGBuilder& GraphBuilder,
|
|
const TArray<FViewInfo>& Views,
|
|
const FLumenSceneFrameTemporaries& FrameTemporaries,
|
|
TRDGUniformBufferRef<FLumenCardScene> LumenCardSceneUniformBuffer,
|
|
const LumenSceneDirectLighting::FLightDataParameters& LumenLightData,
|
|
FRDGBufferSRVRef ShadowMaskTilesSRV,
|
|
FRDGBufferSRVRef CardTilesSRV,
|
|
FRDGBufferSRVRef LightTileOffsetNumPerCardTileSRV,
|
|
FRDGBufferSRVRef LightTilesPerCardTileSRV,
|
|
FRDGTextureUAVRef DirectLightingAtlasUAV,
|
|
FRDGBufferRef IndirectArgBuffer,
|
|
bool bHasRectLights,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
FLumenCardBatchDirectLightingCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenCardBatchDirectLightingCS::FParameters>();
|
|
PassParameters->IndirectArgBuffer = IndirectArgBuffer;
|
|
PassParameters->View = Views[0].ViewUniformBuffer;
|
|
PassParameters->LumenCardScene = LumenCardSceneUniformBuffer;
|
|
PassParameters->LumenLightData = LumenLightData;
|
|
PassParameters->ShadowMaskTiles = ShadowMaskTilesSRV;
|
|
PassParameters->CardTiles = CardTilesSRV;
|
|
PassParameters->LightTileOffsetNumPerCardTile = LightTileOffsetNumPerCardTileSRV;
|
|
PassParameters->LightTilesPerCardTile = LightTilesPerCardTileSRV;
|
|
PassParameters->RWDirectLightingAtlas = DirectLightingAtlasUAV;
|
|
PassParameters->RWTileShadowDownsampleFactorAtlas = GraphBuilder.CreateUAV(FrameTemporaries.TileShadowDownsampleFactorAtlas, PF_R32G32B32A32_UINT);
|
|
PassParameters->TargetFormatQuantizationError = Lumen::GetLightingQuantizationError();
|
|
PassParameters->CachedLightingPreExposure = Lumen::GetCachedLightingPreExposure();
|
|
|
|
int32 NumViewOrigins = FrameTemporaries.ViewOrigins.Num();
|
|
for (int32 OriginIndex = 0; OriginIndex < NumViewOrigins; ++OriginIndex)
|
|
{
|
|
const FLumenViewOrigin& ViewOrigin = FrameTemporaries.ViewOrigins[OriginIndex];
|
|
|
|
PassParameters->PreViewTranslationHigh[OriginIndex] = ViewOrigin.PreViewTranslationDF.High;
|
|
PassParameters->PreViewTranslationLow[OriginIndex] = ViewOrigin.PreViewTranslationDF.Low;
|
|
PassParameters->ViewExposure[OriginIndex] = ViewOrigin.LastEyeAdaptationExposure;
|
|
}
|
|
|
|
int32 WaveOpWaveSize = 0;
|
|
|
|
if (GRHISupportsWaveOperations && RHISupportsWaveOperations(Views[0].GetShaderPlatform()))
|
|
{
|
|
// 64 wave size is preferred for FLumenCardBatchDirectLightingCS
|
|
if (GRHIMinimumWaveSize <= 64 && GRHIMaximumWaveSize >= 64)
|
|
{
|
|
WaveOpWaveSize = 64;
|
|
}
|
|
else if (GRHIMinimumWaveSize <= 32 && GRHIMaximumWaveSize >= 32)
|
|
{
|
|
// TODO: wave32 support
|
|
// WaveOpWaveSize = 32;
|
|
}
|
|
}
|
|
|
|
FLumenCardBatchDirectLightingCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FLumenCardBatchDirectLightingCS::FMultiView>(NumViewOrigins > 1);
|
|
PermutationVector.Set<FLumenCardBatchDirectLightingCS::FHasRectLights>(bHasRectLights);
|
|
PermutationVector.Set<FLumenCardBatchDirectLightingCS::FWaveOpWaveSize>(WaveOpWaveSize);
|
|
auto ComputeShader = Views[0].ShaderMap->GetShader<FLumenCardBatchDirectLightingCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("Batched lights"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
IndirectArgBuffer,
|
|
(uint32)ELumenDispatchCardTilesIndirectArgsOffset::OneGroupPerCardTile);
|
|
}
|
|
|
|
struct FViewBatchedLightParameters
|
|
{
|
|
TArray<FPerLightParameters> PerLightTypeParameters[(int32)ELumenLightType::MAX];
|
|
};
|
|
|
|
static void SetPerLightParameters(FPerLightParameters& DstParameters, const FLumenGatheredLight& Light, int32 ViewIndex)
|
|
{
|
|
DstParameters.LightIndex = Light.LightIndex;
|
|
DstParameters.TanLightSourceAngle = FMath::Tan(Light.LightSceneInfo->Proxy->GetLightSourceAngle());
|
|
DstParameters.DeferredLightUniforms = Light.DeferredLightUniformBuffers[ViewIndex];
|
|
}
|
|
|
|
// Compute for each light the shadow mask based on light attenuation properties (distance falloff, light functions, IES, volumetric cloud)
|
|
// This pass allows to pre-cull needs for tracing shadow rays
|
|
static int32 ComputeShadowMaskFromLightAttenuation(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FScene* Scene,
|
|
const FViewInfo& View,
|
|
TRDGUniformBufferRef<FLumenCardScene> LumenCardSceneUniformBuffer,
|
|
TConstArrayView<FLumenGatheredLight> GatheredLights,
|
|
TConstArrayView<int32> StandaloneLightIndices,
|
|
const FViewBatchedLightParameters& ViewBatchedLightParameters,
|
|
const FLumenLightTileScatterParameters& LightTileScatterParameters,
|
|
const LumenSceneDirectLighting::FLightDataParameters& LumenLightData,
|
|
int32 ViewIndex,
|
|
int32 NumViews,
|
|
const bool bHasLightFunctions,
|
|
FRDGBufferUAVRef ShadowMaskTilesUAV,
|
|
FRDGBufferUAVRef ShadowTraceAllocatorUAV,
|
|
FRDGBufferUAVRef ShadowTracesUAV,
|
|
FRDGBufferSRVRef TileShadowDownsampleFactorAtlasSRV,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
check(NumViews <= LUMEN_MAX_VIEWS);
|
|
|
|
auto SetCommonParameters = [&](FLumenDirectLightingNonRayTracedShadowsParameters& CommonParameters, bool bStandaloneLight)
|
|
{
|
|
CommonParameters.IndirectArgBuffer = LightTileScatterParameters.DispatchIndirectArgs;
|
|
CommonParameters.RWShadowMaskTiles = ShadowMaskTilesUAV;
|
|
CommonParameters.RWShadowTraceAllocator = ShadowTraceAllocatorUAV;
|
|
CommonParameters.RWShadowTraces = ShadowTracesUAV;
|
|
CommonParameters.TileShadowDownsampleFactorAtlas = TileShadowDownsampleFactorAtlasSRV;
|
|
|
|
CommonParameters.View = View.ViewUniformBuffer;
|
|
CommonParameters.LumenCardScene = LumenCardSceneUniformBuffer;
|
|
CommonParameters.LightTileScatterParameters = LightTileScatterParameters;
|
|
CommonParameters.LumenLightData = LumenLightData;
|
|
CommonParameters.CardScatterInstanceIndex = 0;
|
|
CommonParameters.ViewIndex = ViewIndex;
|
|
CommonParameters.NumViews = NumViews;
|
|
CommonParameters.DummyZeroForFixingShaderCompilerBug = 0;
|
|
CommonParameters.ForwardLightStruct = View.ForwardLightingResources.ForwardLightUniformBuffer;
|
|
CommonParameters.MaxTraceDistance = Lumen::GetMaxTraceDistance(View);
|
|
CommonParameters.StepFactor = FMath::Clamp(GOffscreenShadowingTraceStepFactor, .1f, 10.0f);
|
|
CommonParameters.HeightfieldShadowReceiverBias = Lumen::GetHeightfieldReceiverBias();
|
|
CommonParameters.bAdaptiveShadowTracing = CVarLumenDirectLightingHWRTAdaptiveShadowTracing.GetValueOnRenderThread();
|
|
|
|
if (bStandaloneLight)
|
|
{
|
|
CommonParameters.LightTileScatterParameters.bUseLightTilesPerLightType = 0;
|
|
}
|
|
};
|
|
|
|
int32 NumLightsNeedShadowMasks = StandaloneLightIndices.Num();
|
|
|
|
for (const int32 StandaloneLightIndex : StandaloneLightIndices)
|
|
{
|
|
const FLumenGatheredLight& Light = GatheredLights[StandaloneLightIndex];
|
|
check(Light.NeedsShadowMask());
|
|
|
|
const FMaterialRenderProxy* LightFunctionMaterialProxy = Light.LightFunctionMaterialProxy;
|
|
const bool bMayUseCloudTransmittance = GLumenDirectLightingCloudTransmittance != 0 && Light.bMayCastCloudTransmittance;
|
|
const uint32 SlotIndex = LumenSceneDirectLighting::NumBatchableLightTypes + Light.LightIndex;
|
|
const uint32 DispatchIndirectArgOffset = (SlotIndex * NumViews + ViewIndex) * sizeof(FRHIDispatchIndirectParameters);
|
|
|
|
if (LightFunctionMaterialProxy)
|
|
{
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FParameters>();
|
|
SetCommonParameters(PassParameters->Common, true);
|
|
SetPerLightParameters(PassParameters->Common.LightParameters, Light, ViewIndex);
|
|
const bool bUseCloudTransmittance = SetupLightCloudTransmittanceParameters(
|
|
GraphBuilder,
|
|
Scene,
|
|
View,
|
|
bMayUseCloudTransmittance ? Light.LightSceneInfo : nullptr,
|
|
PassParameters->Common.LightCloudTransmittanceParameters);
|
|
SetupLightFunctionParameters(View, Light.LightSceneInfo, 1.0f, PassParameters->LightFunctionParameters);
|
|
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FThreadGroupSize32>(Lumen::UseThreadGroupSize32());
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FCompactShadowTraces>(ShadowTraceAllocatorUAV != nullptr);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FLightType>(Light.Type);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS::FCloudTransmittance>(bUseCloudTransmittance);
|
|
|
|
const FMaterial& Material = LightFunctionMaterialProxy->GetMaterialWithFallback(Scene->GetFeatureLevel(), LightFunctionMaterialProxy);
|
|
const FMaterialShaderMap* MaterialShaderMap = Material.GetRenderingThreadShaderMap();
|
|
TShaderRef<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS> ComputeShader = MaterialShaderMap->GetShader<FLumenDirectLightingShadowMaskFromLightAttenuationWithLightFunctionCS>(PermutationVector);
|
|
|
|
FRDGBufferRef IndirectArgsBuffer = LightTileScatterParameters.DispatchIndirectArgs;
|
|
ClearUnusedGraphResources(ComputeShader, PassParameters, { IndirectArgsBuffer });
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("ShadowMaskFromLightAttenuationPass(LF,%s)", *Light.Name),
|
|
PassParameters,
|
|
ComputePassFlags,
|
|
[PassParameters, ComputeShader, IndirectArgsBuffer, DispatchIndirectArgOffset, LightFunctionMaterialProxy, &Material, &View](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList)
|
|
{
|
|
IndirectArgsBuffer->MarkResourceAsUsed();
|
|
FComputeShaderUtils::ValidateIndirectArgsBuffer(IndirectArgsBuffer, DispatchIndirectArgOffset);
|
|
FRHIComputeShader* ShaderRHI = ComputeShader.GetComputeShader();
|
|
SetComputePipelineState(RHICmdList, ShaderRHI);
|
|
SetShaderParameters(RHICmdList, ComputeShader, ShaderRHI, *PassParameters);
|
|
ComputeShader->SetParameters(RHICmdList, ShaderRHI, LightFunctionMaterialProxy, Material, View);
|
|
RHICmdList.DispatchIndirectComputeShader(IndirectArgsBuffer->GetIndirectRHICallBuffer(), DispatchIndirectArgOffset);
|
|
UnsetShaderUAVs(RHICmdList, ComputeShader, ShaderRHI);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FParameters>();
|
|
SetCommonParameters(PassParameters->Common, true);
|
|
SetPerLightParameters(PassParameters->Common.LightParameters, Light, ViewIndex);
|
|
const bool bUseCloudTransmittance = SetupLightCloudTransmittanceParameters(
|
|
GraphBuilder,
|
|
Scene,
|
|
View,
|
|
bMayUseCloudTransmittance ? Light.LightSceneInfo : nullptr,
|
|
PassParameters->Common.LightCloudTransmittanceParameters);
|
|
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FThreadGroupSize32>(Lumen::UseThreadGroupSize32());
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FCompactShadowTraces>(ShadowTraceAllocatorUAV != nullptr);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FLightType>(Light.Type);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FCloudTransmittance>(bUseCloudTransmittance);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FLightFunctionAtlas>(false);
|
|
TShaderRef<FLumenDirectLightingShadowMaskFromLightAttenuationCS> ComputeShader = View.ShaderMap->GetShader<FLumenDirectLightingShadowMaskFromLightAttenuationCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("ShadowMaskFromLightAttenuationPass(%s)", *Light.Name),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
LightTileScatterParameters.DispatchIndirectArgs,
|
|
DispatchIndirectArgOffset);
|
|
}
|
|
}
|
|
|
|
const bool bUseLightFunctionAtlas = bHasLightFunctions && LightFunctionAtlas::IsEnabled(View, ELightFunctionAtlasSystem::Lumen);
|
|
for (int32 LightTypeIndex = 0; LightTypeIndex < (int32)ELumenLightType::MAX; ++LightTypeIndex)
|
|
{
|
|
TConstArrayView<FPerLightParameters> BatchedLightParameters = ViewBatchedLightParameters.PerLightTypeParameters[LightTypeIndex];
|
|
NumLightsNeedShadowMasks += BatchedLightParameters.Num();
|
|
|
|
if (BatchedLightParameters.Num() > 0)
|
|
{
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FParameters>();
|
|
SetCommonParameters(PassParameters->Common, false);
|
|
SetupLightCloudTransmittanceParameters(GraphBuilder, Scene, View, nullptr, PassParameters->Common.LightCloudTransmittanceParameters);
|
|
if (bUseLightFunctionAtlas)
|
|
{
|
|
PassParameters->LightFunctionAtlas = LightFunctionAtlas::BindGlobalParameters(GraphBuilder, View);
|
|
}
|
|
|
|
FLumenDirectLightingShadowMaskFromLightAttenuationCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FThreadGroupSize32>(Lumen::UseThreadGroupSize32());
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FCompactShadowTraces>(ShadowTraceAllocatorUAV != nullptr);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FLightType>((ELumenLightType)LightTypeIndex);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FCloudTransmittance>(false);
|
|
PermutationVector.Set<FLumenDirectLightingShadowMaskFromLightAttenuationCS::FLightFunctionAtlas>(bUseLightFunctionAtlas);
|
|
TShaderRef<FLumenDirectLightingShadowMaskFromLightAttenuationCS> ComputeShader = View.ShaderMap->GetShader<FLumenDirectLightingShadowMaskFromLightAttenuationCS>(PermutationVector);
|
|
|
|
if (LumenSceneDirectLighting::UseLightTilesPerLightType())
|
|
{
|
|
check(LightTypeIndex > 0);
|
|
const uint32 IndirectArgsOffset = ((LightTypeIndex - 1) * NumViews + ViewIndex) * sizeof(FRHIDispatchIndirectParameters);
|
|
|
|
// This is skipped via a dynamic branch so not used but still needs to be bound
|
|
PassParameters->Common.LightParameters = BatchedLightParameters[0];
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("ShadowMaskFromLightAttenuationPass(LightType=%d)", LightTypeIndex),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
LightTileScatterParameters.DispatchIndirectArgs,
|
|
IndirectArgsOffset);
|
|
}
|
|
else
|
|
{
|
|
const FShaderParametersMetadata* ParametersMetaData = FLumenDirectLightingShadowMaskFromLightAttenuationCS::FParameters::FTypeInfo::GetStructMetadata();
|
|
FRDGBufferRef IndirectArgsBuffer = LightTileScatterParameters.DispatchIndirectArgs;
|
|
ClearUnusedGraphResourcesImpl(ComputeShader->Bindings, ParametersMetaData, PassParameters, { IndirectArgsBuffer });
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("ShadowMaskFromLightAttenuationPass(LightType=%d,BatchedNum=%d)", LightTypeIndex, BatchedLightParameters.Num()),
|
|
PassParameters,
|
|
ComputePassFlags,
|
|
[PassParameters, ComputeShader, IndirectArgsBuffer, NumViews, ViewIndex, BatchedLightParameters](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList)
|
|
{
|
|
// Marks the indirect draw parameter as used by the pass manually, given it can't be bound directly by any of the shader,
|
|
// meaning SetShaderParameters() won't be able to do it.
|
|
IndirectArgsBuffer->MarkResourceAsUsed();
|
|
|
|
for (const FPerLightParameters& LightParameterValues : BatchedLightParameters)
|
|
{
|
|
const uint32 SlotIndex = LumenSceneDirectLighting::NumBatchableLightTypes + LightParameterValues.LightIndex;
|
|
const uint32 IndirectArgsOffset = (SlotIndex * NumViews + ViewIndex) * sizeof(FRHIDispatchIndirectParameters);
|
|
|
|
// TODO: Only set changed paramters
|
|
PassParameters->Common.LightParameters = LightParameterValues;
|
|
FComputeShaderUtils::DispatchIndirect(RHICmdList, ComputeShader, *PassParameters, IndirectArgsBuffer->GetIndirectRHICallBuffer(), IndirectArgsOffset);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return NumLightsNeedShadowMasks;
|
|
}
|
|
|
|
void TraceDistanceFieldShadows(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FScene* Scene,
|
|
const FViewInfo& View,
|
|
TRDGUniformBufferRef<FLumenCardScene> LumenCardSceneUniformBuffer,
|
|
TConstArrayView<FLumenGatheredLight> GatheredLights,
|
|
TConstArrayView<int32> StandaloneLightIndices,
|
|
FViewBatchedLightParameters& ViewBatchedLightParameters,
|
|
const FLumenLightTileScatterParameters& LightTileScatterParameters,
|
|
const LumenSceneDirectLighting::FLightDataParameters& LumenLightData,
|
|
const FDistanceFieldObjectBufferParameters& ObjectBufferParameters,
|
|
int32 ViewIndex,
|
|
int32 NumViews,
|
|
FRDGBufferUAVRef ShadowMaskTilesUAV,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
extern int32 GDistanceFieldOffsetDataStructure;
|
|
extern float GDFShadowTwoSidedMeshDistanceBiasScale;
|
|
|
|
auto SetCommonParameters = [&](
|
|
FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FParameters* PassParameters,
|
|
const FLightTileIntersectionParameters& LightTileIntersectionParameters,
|
|
const FMatrix& WorldToMeshSDFShadowValue,
|
|
bool bStandaloneLight)
|
|
{
|
|
PassParameters->IndirectArgBuffer = LightTileScatterParameters.DispatchIndirectArgs;
|
|
PassParameters->RWShadowMaskTiles = ShadowMaskTilesUAV;
|
|
|
|
PassParameters->View = View.ViewUniformBuffer;
|
|
PassParameters->LumenCardScene = LumenCardSceneUniformBuffer;
|
|
PassParameters->LightTileScatterParameters = LightTileScatterParameters;
|
|
PassParameters->LumenLightData = LumenLightData;
|
|
PassParameters->ViewIndex = ViewIndex;
|
|
PassParameters->NumViews = NumViews;
|
|
PassParameters->DummyZeroForFixingShaderCompilerBug = 0;
|
|
|
|
PassParameters->ObjectBufferParameters = ObjectBufferParameters;
|
|
PassParameters->LightTileIntersectionParameters = LightTileIntersectionParameters;
|
|
|
|
FDistanceFieldAtlasParameters DistanceFieldAtlasParameters = DistanceField::SetupAtlasParameters(GraphBuilder, Scene->DistanceFieldSceneData);
|
|
|
|
PassParameters->DistanceFieldAtlasParameters = DistanceFieldAtlasParameters;
|
|
PassParameters->TranslatedWorldToShadow = FMatrix44f(FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation()) * WorldToMeshSDFShadowValue);
|
|
PassParameters->TwoSidedMeshDistanceBiasScale = GDFShadowTwoSidedMeshDistanceBiasScale;
|
|
|
|
PassParameters->MaxTraceDistance = Lumen::GetMaxTraceDistance(View);
|
|
PassParameters->StepFactor = FMath::Clamp(GOffscreenShadowingTraceStepFactor, .1f, 10.0f);
|
|
PassParameters->MeshSDFShadowRayBias = LumenSceneDirectLighting::GetMeshSDFShadowRayBias();
|
|
PassParameters->HeightfieldShadowRayBias = LumenSceneDirectLighting::GetHeightfieldShadowRayBias();
|
|
PassParameters->GlobalSDFShadowRayBias = LumenSceneDirectLighting::GetGlobalSDFShadowRayBias();
|
|
PassParameters->HeightfieldMaxTracingSteps = Lumen::GetHeightfieldMaxTracingSteps();
|
|
|
|
if (bStandaloneLight)
|
|
{
|
|
PassParameters->LightTileScatterParameters.bUseLightTilesPerLightType = 0;
|
|
}
|
|
};
|
|
|
|
const bool bThreadGroupSize32 = Lumen::UseThreadGroupSize32();
|
|
const bool bTraceGlobalSDF = Lumen::UseGlobalSDFTracing(View.Family->EngineShowFlags);
|
|
const bool bSimpleCoverageBasedExpand = bTraceGlobalSDF && Lumen::UseGlobalSDFSimpleCoverageBasedExpand();
|
|
|
|
for (const int32 StandaloneLightIndex : StandaloneLightIndices)
|
|
{
|
|
const FLumenGatheredLight& Light = GatheredLights[StandaloneLightIndex];
|
|
|
|
if (!Light.bHasShadows)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const FLumenSceneData& LumenSceneData = *Scene->GetLumenSceneData(View);
|
|
|
|
FLightTileIntersectionParameters LightTileIntersectionParameters;
|
|
FMatrix WorldToMeshSDFShadowValue = FMatrix::Identity;
|
|
|
|
// Whether to trace individual mesh SDFs or heightfield objects for higher quality offscreen shadowing
|
|
const bool bTraceMeshObjects = Light.bHasShadows
|
|
&& Light.Type == ELumenLightType::Directional
|
|
&& DoesPlatformSupportDistanceFieldShadowing(View.GetShaderPlatform())
|
|
&& GLumenDirectLightingOffscreenShadowingTraceMeshSDFs != 0;
|
|
|
|
const bool bTraceMeshSDFs = bTraceMeshObjects
|
|
&& Lumen::UseMeshSDFTracing(View.Family->EngineShowFlags)
|
|
&& ObjectBufferParameters.NumSceneObjects > 0;
|
|
|
|
const bool bTraceHeighfieldObjects = bTraceMeshObjects
|
|
&& Lumen::UseHeightfieldTracing(*View.Family, LumenSceneData);
|
|
|
|
if (bTraceMeshSDFs)
|
|
{
|
|
CullMeshObjectsForLightCards(
|
|
GraphBuilder,
|
|
Scene,
|
|
//@todo - this breaks second view if far away
|
|
View,
|
|
Light.LightSceneInfo,
|
|
DFPT_SignedDistanceField,
|
|
ObjectBufferParameters,
|
|
WorldToMeshSDFShadowValue,
|
|
LightTileIntersectionParameters);
|
|
}
|
|
|
|
if (bTraceHeighfieldObjects)
|
|
{
|
|
FLightTileIntersectionParameters LightTileHeightfieldIntersectionParameters;
|
|
|
|
CullMeshObjectsForLightCards(
|
|
GraphBuilder,
|
|
Scene,
|
|
View,
|
|
Light.LightSceneInfo,
|
|
DFPT_HeightField,
|
|
ObjectBufferParameters,
|
|
WorldToMeshSDFShadowValue,
|
|
LightTileHeightfieldIntersectionParameters);
|
|
|
|
if (!bTraceMeshSDFs)
|
|
{
|
|
LightTileIntersectionParameters = LightTileHeightfieldIntersectionParameters;
|
|
}
|
|
|
|
LightTileIntersectionParameters.HeightfieldShadowTileNumCulledObjects = LightTileHeightfieldIntersectionParameters.ShadowTileNumCulledObjects;
|
|
LightTileIntersectionParameters.HeightfieldShadowTileStartOffsets = LightTileHeightfieldIntersectionParameters.ShadowTileStartOffsets;
|
|
LightTileIntersectionParameters.HeightfieldShadowTileArrayData = LightTileHeightfieldIntersectionParameters.ShadowTileArrayData;
|
|
}
|
|
|
|
FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FParameters>();
|
|
SetCommonParameters(PassParameters, LightTileIntersectionParameters, WorldToMeshSDFShadowValue, true);
|
|
SetPerLightParameters(PassParameters->LightParameters, Light, ViewIndex);
|
|
|
|
FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FThreadGroupSize32>(bThreadGroupSize32);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FLightType>(Light.Type);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FTraceGlobalSDF>(bTraceGlobalSDF);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FSimpleCoverageBasedExpand>(bSimpleCoverageBasedExpand);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FTraceMeshSDFs>(bTraceMeshSDFs);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FTraceHeightfields>(bTraceHeighfieldObjects);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FOffsetDataStructure>(GDistanceFieldOffsetDataStructure);
|
|
PermutationVector = FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::RemapPermutation(PermutationVector);
|
|
|
|
TShaderRef<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS> ComputeShader = View.ShaderMap->GetShader<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS>(PermutationVector);
|
|
|
|
const uint32 SlotIndex = LumenSceneDirectLighting::NumBatchableLightTypes + Light.LightIndex;
|
|
const uint32 DispatchIndirectArgOffset = (SlotIndex * NumViews + ViewIndex) * sizeof(FRHIDispatchIndirectParameters);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("DistanceFieldShadowPass %s", *Light.Name),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
LightTileScatterParameters.DispatchIndirectArgs,
|
|
DispatchIndirectArgOffset);
|
|
}
|
|
|
|
for (int32 LightTypeIndex = 0; LightTypeIndex < (int32)ELumenLightType::MAX; ++LightTypeIndex)
|
|
{
|
|
TArray<FPerLightParameters>& BatchedLightParameters = ViewBatchedLightParameters.PerLightTypeParameters[LightTypeIndex];
|
|
|
|
if (BatchedLightParameters.Num() > 0)
|
|
{
|
|
FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FParameters>();
|
|
SetCommonParameters(PassParameters, FLightTileIntersectionParameters(), FMatrix::Identity, false);
|
|
|
|
FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FThreadGroupSize32>(bThreadGroupSize32);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FLightType>((ELumenLightType)LightTypeIndex);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FTraceGlobalSDF>(bTraceGlobalSDF);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FSimpleCoverageBasedExpand>(bSimpleCoverageBasedExpand);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FTraceMeshSDFs>(false);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FTraceHeightfields>(false);
|
|
PermutationVector.Set<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FOffsetDataStructure>(GDistanceFieldOffsetDataStructure);
|
|
PermutationVector = FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::RemapPermutation(PermutationVector);
|
|
|
|
TShaderRef<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS> ComputeShader = View.ShaderMap->GetShader<FLumenSceneDirectLightingTraceDistanceFieldShadowsCS>(PermutationVector);
|
|
|
|
if (LumenSceneDirectLighting::UseLightTilesPerLightType())
|
|
{
|
|
check(LightTypeIndex > 0);
|
|
const uint32 IndirectArgsOffset = ((LightTypeIndex - 1) * NumViews + ViewIndex) * sizeof(FRHIDispatchIndirectParameters);
|
|
|
|
// This is skipped via a dynamic branch so not used but still needs to be bound
|
|
PassParameters->LightParameters = BatchedLightParameters[0];
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("DistanceFieldShadowPass LightType=%d", LightTypeIndex),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
LightTileScatterParameters.DispatchIndirectArgs,
|
|
IndirectArgsOffset);
|
|
}
|
|
else
|
|
{
|
|
const FShaderParametersMetadata* ParametersMetaData = FLumenSceneDirectLightingTraceDistanceFieldShadowsCS::FParameters::FTypeInfo::GetStructMetadata();
|
|
FRDGBufferRef IndirectArgsBuffer = LightTileScatterParameters.DispatchIndirectArgs;
|
|
ClearUnusedGraphResourcesImpl(ComputeShader->Bindings, ParametersMetaData, PassParameters, { IndirectArgsBuffer });
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("DistanceFieldShadowPass LightType=%d BatchedNum=%d", LightTypeIndex, BatchedLightParameters.Num()),
|
|
PassParameters,
|
|
ComputePassFlags,
|
|
[PassParameters, ComputeShader, IndirectArgsBuffer, NumViews, ViewIndex, LocalBatchedLightParameters = MoveTemp(BatchedLightParameters)](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList) mutable
|
|
{
|
|
// Marks the indirect draw parameter as used by the pass manually, given it can't be bound directly by any of the shader,
|
|
// meaning SetShaderParameters() won't be able to do it.
|
|
IndirectArgsBuffer->MarkResourceAsUsed();
|
|
|
|
for (FPerLightParameters& LightParameterValues : LocalBatchedLightParameters)
|
|
{
|
|
const uint32 SlotIndex = LumenSceneDirectLighting::NumBatchableLightTypes + LightParameterValues.LightIndex;
|
|
const uint32 IndirectArgsOffset = (SlotIndex * NumViews + ViewIndex) * sizeof(FRHIDispatchIndirectParameters);
|
|
|
|
// TODO: Only set changed paramters
|
|
PassParameters->LightParameters = MoveTemp(LightParameterValues);
|
|
FComputeShaderUtils::DispatchIndirect(RHICmdList, ComputeShader, *PassParameters, IndirectArgsBuffer->GetIndirectRHICallBuffer(), IndirectArgsOffset);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Must match FLumenPackedLight in LumenSceneDirectLighting.ush
|
|
struct FLumenPackedLight
|
|
{
|
|
FVector3f WorldPositionHigh;
|
|
uint32 LightingChannelMask;
|
|
|
|
FVector3f WorldPositionLow;
|
|
float InvRadius;
|
|
|
|
FVector3f Color;
|
|
float FalloffExponent;
|
|
|
|
FVector3f Direction;
|
|
uint32 DiffuseAndSpecularScale;
|
|
|
|
FVector3f Tangent;
|
|
float SourceRadius;
|
|
|
|
FVector2f SpotAngles;
|
|
float SoftSourceRadius;
|
|
float SourceLength;
|
|
|
|
float RectLightBarnCosAngle;
|
|
float RectLightBarnLength;
|
|
float RectLightAtlasMaxLevel;
|
|
uint32 LightType;
|
|
|
|
FVector2f SinCosConeAngleOrRectLightAtlasUVScale;
|
|
FVector2f RectLightAtlasUVOffset;
|
|
|
|
uint32 LightFunctionAtlasIndex_bHasShadowMask_bIsStandalone_bCastDynamicShadows;
|
|
float IESAtlasIndex;
|
|
float InverseExposureBlend;
|
|
float Padding0;
|
|
};
|
|
|
|
struct FLightTileCullContext
|
|
{
|
|
FLumenLightTileScatterParameters LightTileScatterParameters;
|
|
FRDGBufferRef LightTileAllocator;
|
|
FRDGBufferRef LightTiles;
|
|
FRDGBufferRef DispatchLightTilesIndirectArgs;
|
|
|
|
FRDGBufferRef LightTileOffsetNumPerCardTile;
|
|
FRDGBufferRef LightTilesPerCardTile;
|
|
uint32 MaxCulledCardTiles;
|
|
};
|
|
|
|
// Build list of surface cache tiles per light for future processing
|
|
static void CullDirectLightingTiles(
|
|
FRDGBuilder& GraphBuilder,
|
|
const TArray<FViewInfo>& Views,
|
|
const FLumenSceneFrameTemporaries& FrameTemporaries,
|
|
const FLumenCardUpdateContext& CardUpdateContext,
|
|
TRDGUniformBufferRef<FLumenCardScene> LumenCardSceneUniformBuffer,
|
|
TConstArrayView<FLumenGatheredLight> GatheredLights,
|
|
TConstArrayView<int32> StandaloneLightIndices,
|
|
const LumenSceneDirectLighting::FLightDataParameters& LumenLightData,
|
|
FLightTileCullContext& CullContext,
|
|
FLumenCardTileUpdateContext& CardTileUpdateContext,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "CullTiles %d lights", GatheredLights.Num());
|
|
const FGlobalShaderMap* GlobalShaderMap = Views[0].ShaderMap;
|
|
|
|
int32 NumViewOrigins = FrameTemporaries.ViewOrigins.Num();
|
|
|
|
const uint32 MaxLightTiles = CardUpdateContext.MaxUpdateTiles;
|
|
const uint32 NumLightSlots = LumenSceneDirectLighting::NumBatchableLightTypes + GatheredLights.Num();
|
|
const uint32 NumLightsRoundedUp = FMath::RoundUpToPowerOfTwo(NumLightSlots) * NumViewOrigins;
|
|
const uint32 MaxLightsPerTile = FMath::RoundUpToPowerOfTwo(FMath::Clamp(CVarLumenDirectLightingMaxLightsPerTile.GetValueOnRenderThread(), 1, 32));
|
|
const uint32 MaxCulledCardTiles = MaxLightsPerTile * MaxLightTiles;
|
|
|
|
Lumen::SpliceCardPagesIntoTiles(GraphBuilder, GlobalShaderMap, CardUpdateContext, LumenCardSceneUniformBuffer, CardTileUpdateContext, ComputePassFlags);
|
|
|
|
const bool bCullToCardTileDepthRange = CVarLumenDirectLightingCullToTileDepthRange.GetValueOnRenderThread() != 0;
|
|
|
|
FRDGBufferRef CardTileDepthRanges = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), bCullToCardTileDepthRange ? MaxLightTiles : 1), TEXT("Lumen.CardTileDepthRanges"));
|
|
FRDGBufferRef CardTileAllocator = CardTileUpdateContext.CardTileAllocator;
|
|
FRDGBufferRef CardTiles = CardTileUpdateContext.CardTiles;
|
|
FRDGBufferRef DispatchCardTilesIndirectArgs = CardTileUpdateContext.DispatchCardTilesIndirectArgs;
|
|
|
|
// Calculate min and max card tile depth for better light culling
|
|
if (bCullToCardTileDepthRange)
|
|
{
|
|
FCalculateCardTileDepthRangesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FCalculateCardTileDepthRangesCS::FParameters>();
|
|
PassParameters->IndirectArgBuffer = DispatchCardTilesIndirectArgs;
|
|
PassParameters->View = Views[0].ViewUniformBuffer;
|
|
PassParameters->LumenCardScene = LumenCardSceneUniformBuffer;
|
|
PassParameters->RWCardTileDepthRanges = GraphBuilder.CreateUAV(CardTileDepthRanges);
|
|
PassParameters->CardTileAllocator = GraphBuilder.CreateSRV(CardTileAllocator);
|
|
PassParameters->CardTiles = GraphBuilder.CreateSRV(CardTiles);
|
|
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FCalculateCardTileDepthRangesCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("CalculateCardTileDepthRanges"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
DispatchCardTilesIndirectArgs,
|
|
(uint32)ELumenDispatchCardTilesIndirectArgsOffset::OneGroupPerCardTile);
|
|
}
|
|
|
|
FRDGBufferRef LightTileAllocator = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), 1), TEXT("Lumen.DirectLighting.LightTileAllocator"));
|
|
FRDGBufferRef LightTiles = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(2 * sizeof(uint32), MaxCulledCardTiles), TEXT("Lumen.DirectLighting.LightTiles"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(LightTileAllocator), 0, ComputePassFlags);
|
|
|
|
FRDGBufferRef LightTileAllocatorPerLight = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), NumLightsRoundedUp), TEXT("Lumen.DirectLighting.LightTileAllocatorPerLight"));
|
|
FRDGBufferRef LightTileOffsetsPerLight = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), NumLightsRoundedUp), TEXT("Lumen.DirectLighting.LightTileOffsetsPerLight"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(LightTileAllocatorPerLight), 0, ComputePassFlags);
|
|
|
|
// Used to figure out the offset to store light tiles for each card tile
|
|
FRDGBufferRef LightTileAllocatorForPerCardTileDispatch = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), 1), TEXT("Lumen.DirectLighting.LightTileAllocatorForPerCardTileDispatch"));
|
|
FRDGBufferRef LightTileOffsetNumPerCardTile = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), MaxLightTiles), TEXT("Lumen.DirectLighting.LightTileOffsetNumPerCardTile"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(LightTileAllocatorForPerCardTileDispatch), 0, ComputePassFlags);
|
|
|
|
// Build a list of light tiles for future processing
|
|
{
|
|
FBuildLightTilesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FBuildLightTilesCS::FParameters>();
|
|
PassParameters->IndirectArgBuffer = DispatchCardTilesIndirectArgs;
|
|
PassParameters->View = Views[0].ViewUniformBuffer;
|
|
PassParameters->LumenCardScene = LumenCardSceneUniformBuffer;
|
|
PassParameters->LumenLightData = LumenLightData;
|
|
PassParameters->RWLightTileAllocator = GraphBuilder.CreateUAV(LightTileAllocator);
|
|
PassParameters->RWLightTileAllocatorForPerCardTileDispatch = GraphBuilder.CreateUAV(LightTileAllocatorForPerCardTileDispatch);
|
|
PassParameters->RWLightTiles = GraphBuilder.CreateUAV(LightTiles);
|
|
PassParameters->RWLightTileAllocatorPerLight = GraphBuilder.CreateUAV(LightTileAllocatorPerLight);
|
|
PassParameters->RWLightTileOffsetNumPerCardTile = GraphBuilder.CreateUAV(LightTileOffsetNumPerCardTile);
|
|
PassParameters->CardTileAllocator = GraphBuilder.CreateSRV(CardTileAllocator);
|
|
PassParameters->CardTiles = GraphBuilder.CreateSRV(CardTiles);
|
|
PassParameters->CardTileDepthRanges = bCullToCardTileDepthRange ? GraphBuilder.CreateSRV(CardTileDepthRanges) : PassParameters->CardTiles;
|
|
PassParameters->CullToCardTileDepthRange = bCullToCardTileDepthRange ? 1 : 0;
|
|
PassParameters->MaxLightsPerTile = MaxLightsPerTile;
|
|
PassParameters->NumLights = GatheredLights.Num();
|
|
PassParameters->NumViews = NumViewOrigins;
|
|
PassParameters->bUseLightTilesPerLightType = LumenSceneDirectLighting::UseLightTilesPerLightType() ? 1 : 0;
|
|
check(NumViewOrigins <= PassParameters->FrustumTranslatedWorldToClip.Num());
|
|
|
|
for (int32 OriginIndex = 0; OriginIndex < NumViewOrigins; ++OriginIndex)
|
|
{
|
|
const FLumenViewOrigin& ViewOrigin = FrameTemporaries.ViewOrigins[OriginIndex];
|
|
|
|
PassParameters->FrustumTranslatedWorldToClip[OriginIndex] = ViewOrigin.FrustumTranslatedWorldToClip;
|
|
PassParameters->PreViewTranslationHigh[OriginIndex] = ViewOrigin.PreViewTranslationDF.High;
|
|
PassParameters->PreViewTranslationLow[OriginIndex] = ViewOrigin.PreViewTranslationDF.Low;
|
|
PassParameters->ViewExposure[OriginIndex] = ViewOrigin.LastEyeAdaptationExposure;
|
|
}
|
|
|
|
FBuildLightTilesCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FBuildLightTilesCS::FMaxLightSamples>(MaxLightsPerTile);
|
|
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FBuildLightTilesCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("BuildLightTiles"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
DispatchCardTilesIndirectArgs,
|
|
(uint32)ELumenDispatchCardTilesIndirectArgsOffset::OneThreadPerCardTile);
|
|
}
|
|
|
|
// Compute prefix sum for card tile array
|
|
{
|
|
const bool bUseStandaloneLightIndices = LumenSceneDirectLighting::UseLightTilesPerLightType();
|
|
|
|
FComputeLightTileOffsetsPerLightCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FComputeLightTileOffsetsPerLightCS::FParameters>();
|
|
PassParameters->RWLightTileOffsetsPerLight = GraphBuilder.CreateUAV(LightTileOffsetsPerLight);
|
|
PassParameters->LightTileAllocatorPerLight = GraphBuilder.CreateSRV(LightTileAllocatorPerLight);
|
|
PassParameters->NumLights = GatheredLights.Num();
|
|
PassParameters->NumViews = NumViewOrigins;
|
|
if (bUseStandaloneLightIndices)
|
|
{
|
|
FRDGBufferRef StandaloneLightIndicesBuffer = CreateStructuredBuffer(GraphBuilder, TEXT("Lumen.DirectLighting.StandaloneLightIndices"), StandaloneLightIndices, ERDGInitialDataFlags::NoCopy);
|
|
PassParameters->StandaloneLightIndices = GraphBuilder.CreateSRV(StandaloneLightIndicesBuffer);
|
|
PassParameters->NumStandaloneLights = (uint32)StandaloneLightIndices.Num();
|
|
}
|
|
|
|
FComputeLightTileOffsetsPerLightCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FComputeLightTileOffsetsPerLightCS::FUseStandaloneLightIndices>(bUseStandaloneLightIndices);
|
|
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FComputeLightTileOffsetsPerLightCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("ComputeLightTileOffsetsPerLight"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(1, 1, 1));
|
|
}
|
|
|
|
enum class EDispatchTilesIndirectArgOffset
|
|
{
|
|
NumTilesDiv1 = 0 * sizeof(FRHIDispatchIndirectParameters),
|
|
NumTilesDiv64 = 1 * sizeof(FRHIDispatchIndirectParameters),
|
|
MAX = 2,
|
|
};
|
|
|
|
// Initialize indirect args for culled tiles
|
|
FRDGBufferRef DispatchLightTilesIndirectArgs = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>((int32)EDispatchTilesIndirectArgOffset::MAX), TEXT("Lumen.DirectLighting.DispatchLightTilesIndirectArgs"));
|
|
FRDGBufferRef DrawTilesPerLightIndirectArgs = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDrawIndirectParameters>(NumLightsRoundedUp), TEXT("Lumen.DirectLighting.DrawTilesPerLightIndirectArgs"));
|
|
FRDGBufferRef DispatchTilesPerLightIndirectArgs = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(NumLightsRoundedUp), TEXT("Lumen.DirectLighting.DispatchTilesPerLightIndirectArgs"));
|
|
{
|
|
FInitializeLightTileIndirectArgsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FInitializeLightTileIndirectArgsCS::FParameters>();
|
|
PassParameters->RWDispatchLightTilesIndirectArgs = GraphBuilder.CreateUAV(DispatchLightTilesIndirectArgs);
|
|
PassParameters->RWDrawTilesPerLightIndirectArgs = GraphBuilder.CreateUAV(DrawTilesPerLightIndirectArgs);
|
|
PassParameters->RWDispatchTilesPerLightIndirectArgs = GraphBuilder.CreateUAV(DispatchTilesPerLightIndirectArgs);
|
|
PassParameters->LightTileAllocator = GraphBuilder.CreateSRV(LightTileAllocator);
|
|
PassParameters->LightTileAllocatorPerLight = GraphBuilder.CreateSRV(LightTileAllocatorPerLight);
|
|
PassParameters->VertexCountPerInstanceIndirect = GRHISupportsRectTopology ? 3 : 6;
|
|
PassParameters->PerLightDispatchFactor = Lumen::UseThreadGroupSize32() ? 2 : 1;
|
|
PassParameters->NumLights = NumLightSlots;
|
|
PassParameters->NumViews = NumViewOrigins;
|
|
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FInitializeLightTileIndirectArgsCS>();
|
|
|
|
const FIntVector GroupSize = FComputeShaderUtils::GetGroupCount(
|
|
FMath::Max((int32)NumLightSlots * NumViewOrigins, 1), // Dispatch at least one group in order to init global tile indirect arguments
|
|
FInitializeLightTileIndirectArgsCS::GetGroupSize());
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("InitializeLightTileIndirectArgs"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
GroupSize);
|
|
}
|
|
|
|
FRDGBufferRef LightTilesPerCardTile = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(2 * sizeof(uint32), MaxCulledCardTiles), TEXT("Lumen.DirectLighting.LightTilesPerCardTile"));
|
|
|
|
// Compact card tile array
|
|
{
|
|
FRDGBufferRef CompactedLightTiles = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(2 * sizeof(uint32), MaxCulledCardTiles), TEXT("Lumen.DirectLighting.CompactedLightTiles"));
|
|
FRDGBufferRef CompactedLightTileAllocatorPerLight = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), NumLightsRoundedUp), TEXT("Lumen.DirectLighting.CompactedLightTileAllocatorPerLight"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(CompactedLightTileAllocatorPerLight), 0, ComputePassFlags);
|
|
|
|
FCompactLightTilesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FCompactLightTilesCS::FParameters>();
|
|
PassParameters->IndirectArgBuffer = DispatchLightTilesIndirectArgs;
|
|
PassParameters->RWCompactedLightTiles = GraphBuilder.CreateUAV(CompactedLightTiles);
|
|
PassParameters->RWCompactedLightTileAllocatorPerLight = GraphBuilder.CreateUAV(CompactedLightTileAllocatorPerLight);
|
|
PassParameters->RWLightTilesPerCardTile = GraphBuilder.CreateUAV(LightTilesPerCardTile);
|
|
PassParameters->LightTileAllocator = GraphBuilder.CreateSRV(LightTileAllocator);
|
|
PassParameters->LightTiles = GraphBuilder.CreateSRV(LightTiles);
|
|
PassParameters->LightTileOffsetsPerLight = GraphBuilder.CreateSRV(LightTileOffsetsPerLight);
|
|
PassParameters->CardTiles = GraphBuilder.CreateSRV(CardTiles);
|
|
PassParameters->LightTileOffsetNumPerCardTile = GraphBuilder.CreateSRV(LightTileOffsetNumPerCardTile);
|
|
PassParameters->NumLights = GatheredLights.Num();
|
|
PassParameters->NumViews = NumViewOrigins;
|
|
PassParameters->bUseLightTilesPerLightType = LumenSceneDirectLighting::UseLightTilesPerLightType() ? 1 : 0;
|
|
|
|
auto ComputeShader = GlobalShaderMap->GetShader<FCompactLightTilesCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("CompactLightTiles"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
DispatchLightTilesIndirectArgs,
|
|
(int32)EDispatchTilesIndirectArgOffset::NumTilesDiv64);
|
|
|
|
LightTiles = CompactedLightTiles;
|
|
}
|
|
|
|
CullContext.LightTileScatterParameters.DrawIndirectArgs = DrawTilesPerLightIndirectArgs;
|
|
CullContext.LightTileScatterParameters.DispatchIndirectArgs = DispatchTilesPerLightIndirectArgs;
|
|
CullContext.LightTileScatterParameters.LightTileAllocator = GraphBuilder.CreateSRV(LightTileAllocator);
|
|
CullContext.LightTileScatterParameters.LightTiles = GraphBuilder.CreateSRV(LightTiles);
|
|
CullContext.LightTileScatterParameters.LightTileOffsetsPerLight = GraphBuilder.CreateSRV(LightTileOffsetsPerLight);
|
|
CullContext.LightTileScatterParameters.bUseLightTilesPerLightType = LumenSceneDirectLighting::UseLightTilesPerLightType() ? 1 : 0;
|
|
|
|
CullContext.LightTiles = LightTiles;
|
|
CullContext.LightTileAllocator = LightTileAllocator;
|
|
CullContext.DispatchLightTilesIndirectArgs = DispatchLightTilesIndirectArgs;
|
|
|
|
CullContext.LightTileOffsetNumPerCardTile = LightTileOffsetNumPerCardTile;
|
|
CullContext.LightTilesPerCardTile = LightTilesPerCardTile;
|
|
CullContext.MaxCulledCardTiles = MaxCulledCardTiles;
|
|
}
|
|
|
|
struct FLumenDirectLightingTaskData
|
|
{
|
|
mutable UE::Tasks::FTask Task;
|
|
TArray<FLumenGatheredLight, TInlineAllocator<64>> GatheredLights;
|
|
TArray<FLumenPackedLight, TInlineAllocator<16>> PackedLightData;
|
|
TArray<FVector4f> LightInfluenceSpheres;
|
|
// Note: All batched lights cast ray traced shadows
|
|
mutable TArray<FViewBatchedLightParameters, TInlineAllocator<1>> ViewBatchedLightParameters;
|
|
// Note: All standalone (non-batched) lights need shadow masks but may not cast ray traced shadows
|
|
TArray<int32, TInlineAllocator<4>> StandaloneLightIndices;
|
|
// Needed when we batch lights of the same type into a single dispatch. The UB is not accessed but
|
|
// still needs to be bound because it is skipped via a dynamic branch
|
|
TUniformBufferRef<FDeferredLightUniformStruct> DummyLightUniformBuffer;
|
|
bool bHasIESLights = false;
|
|
bool bHasRectLights = false;
|
|
bool bHasLightFunctions = false;
|
|
};
|
|
|
|
uint32 PackRG16(float In0, float In1);
|
|
|
|
void FDeferredShadingSceneRenderer::BeginGatherLumenLights(const FLumenSceneFrameTemporaries& FrameTemporaries, FLumenDirectLightingTaskData*& TaskData, IVisibilityTaskData* VisibilityTaskData, UE::Tasks::FTask UpdateLightFunctionAtlasTask)
|
|
{
|
|
if (HasRayTracedOverlay(ViewFamily))
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool bAnyLumenActive = false;
|
|
|
|
for (const FViewInfo& View : Views)
|
|
{
|
|
const FPerViewPipelineState& ViewPipelineState = GetViewPipelineState(View);
|
|
bAnyLumenActive |= ViewPipelineState.DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
|
|
}
|
|
|
|
if (!bAnyLumenActive || CVarLumenLumenSceneDirectLighting.GetValueOnRenderThread() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TaskData = Allocator.Create<FLumenDirectLightingTaskData>();
|
|
|
|
TArray<UE::Tasks::FTask, TInlineAllocator<2>> Prerequisites;
|
|
Prerequisites.Add(VisibilityTaskData->GetLightVisibilityTask());
|
|
Prerequisites.Add(UpdateLightFunctionAtlasTask);
|
|
|
|
TaskData->Task = LaunchSceneRenderTask(TEXT("GatherLumenLights"), [TaskData, Scene = this->Scene, &Views = this->Views, &ViewFamily = this->ViewFamily, &FrameTemporaries]
|
|
{
|
|
SCOPED_NAMED_EVENT_TEXT("GatherLumenLights", FColor::Green);
|
|
|
|
const bool bUseHardwareRayTracing = Lumen::UseHardwareRayTracedDirectLighting(ViewFamily);
|
|
const bool bUseBatchedShadows = CVarLumenDirectLightingBatchShadows.GetValueOnAnyThread() != 0;
|
|
const bool bUseLightTilesPerLightType = LumenSceneDirectLighting::UseLightTilesPerLightType();
|
|
constexpr int32 NumLightTypes = (int32)ELumenLightType::MAX;
|
|
int32 BatchedLightCounts[NumLightTypes] = {};
|
|
|
|
for (auto LightIt = Scene->Lights.CreateConstIterator(); LightIt; ++LightIt)
|
|
{
|
|
const FLightSceneInfoCompact& LightSceneInfoCompact = *LightIt;
|
|
const FLightSceneInfo* LightSceneInfo = LightSceneInfoCompact.LightSceneInfo;
|
|
|
|
if (LightSceneInfo->ShouldRenderLightViewIndependent()
|
|
&& LightSceneInfo->Proxy->GetIndirectLightingScale() > 0.0f)
|
|
{
|
|
for (const FViewInfo& View : Views)
|
|
{
|
|
if (LightSceneInfo->ShouldRenderLight(View, true))
|
|
{
|
|
const FLumenGatheredLight GatheredLight(Scene, Views, FrameTemporaries, LightSceneInfo, /*LightIndex*/ TaskData->GatheredLights.Num());
|
|
|
|
if (GatheredLight.NeedsShadowMask())
|
|
{
|
|
if (bUseBatchedShadows && GatheredLight.CanUseBatchedShadows())
|
|
{
|
|
++BatchedLightCounts[(int32)GatheredLight.Type];
|
|
}
|
|
else
|
|
{
|
|
TaskData->StandaloneLightIndices.Add(GatheredLight.LightIndex);
|
|
}
|
|
}
|
|
|
|
TaskData->bHasIESLights |= LightSceneInfo->Proxy->GetIESTexture() != nullptr;
|
|
TaskData->bHasRectLights |= GatheredLight.Type == ELumenLightType::Rect;
|
|
TaskData->bHasLightFunctions |= GatheredLight.LightFunctionMaterialProxy != nullptr;
|
|
TaskData->GatheredLights.Add(GatheredLight);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TaskData->PackedLightData.SetNum(FMath::RoundUpToPowerOfTwo(FMath::Max(TaskData->GatheredLights.Num(), 16)));
|
|
TaskData->LightInfluenceSpheres.SetNum(FMath::RoundUpToPowerOfTwo(FMath::Max(TaskData->GatheredLights.Num(), 16)));
|
|
|
|
int32 NumViewOrigins = FrameTemporaries.ViewOrigins.Num();
|
|
|
|
TaskData->ViewBatchedLightParameters.SetNum(NumViewOrigins);
|
|
for (FViewBatchedLightParameters& ViewLightParameters : TaskData->ViewBatchedLightParameters)
|
|
{
|
|
for (int32 LightTypeIndex = 0; LightTypeIndex < NumLightTypes; ++LightTypeIndex)
|
|
{
|
|
if (bUseLightTilesPerLightType && BatchedLightCounts[LightTypeIndex] > 0)
|
|
{
|
|
if (!TaskData->DummyLightUniformBuffer)
|
|
{
|
|
FDeferredLightUniformStruct DeferredLightUniforms;
|
|
FMemory::Memset(&DeferredLightUniforms, 0, sizeof(FDeferredLightUniformStruct));
|
|
TaskData->DummyLightUniformBuffer = CreateUniformBufferImmediate(DeferredLightUniforms, UniformBuffer_SingleFrame);
|
|
}
|
|
FPerLightParameters& LightParameters = ViewLightParameters.PerLightTypeParameters[LightTypeIndex].AddZeroed_GetRef();
|
|
LightParameters.DeferredLightUniforms = TaskData->DummyLightUniformBuffer;
|
|
}
|
|
else
|
|
{
|
|
ViewLightParameters.PerLightTypeParameters[LightTypeIndex].Empty(BatchedLightCounts[LightTypeIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int32 LightIndex = 0; LightIndex < TaskData->GatheredLights.Num(); ++LightIndex)
|
|
{
|
|
const FLumenGatheredLight& LumenLight = TaskData->GatheredLights[LightIndex];
|
|
const FLightSceneInfo* LightSceneInfo = LumenLight.LightSceneInfo;
|
|
const FSphere LightBounds = LightSceneInfo->Proxy->GetBoundingSphere();
|
|
|
|
FVector4f& LightInfluenceSphere = TaskData->LightInfluenceSpheres[LightIndex];
|
|
LightInfluenceSphere = FVector4f(FVector3f(LightBounds.Center), LightBounds.W);
|
|
|
|
FLightRenderParameters ShaderParameters;
|
|
LightSceneInfo->Proxy->GetLightShaderParameters(ShaderParameters);
|
|
|
|
const uint8 LightType = LightSceneInfo->Proxy->GetLightType();
|
|
if (LightType == LightType_Directional && LightSceneInfo->Proxy->GetUsePerPixelAtmosphereTransmittance())
|
|
{
|
|
// When using PerPixelTransmittance, transmittance is evaluated per pixel by sampling the transmittance texture. It gives better gradient on large scale objects such as mountains.
|
|
// However, to skip doing that texture sampling in Lumen card lighting or having the lumen shadow cache forced to be colored, we use the simple planet top ground transmittance as a simplification.
|
|
// That will work for most of the cases for most of the map/terrain at the top of the virtual planet.
|
|
ShaderParameters.Color *= LightSceneInfo->Proxy->GetAtmosphereTransmittanceTowardSun();
|
|
}
|
|
|
|
if (LightSceneInfo->Proxy->IsInverseSquared())
|
|
{
|
|
ShaderParameters.FalloffExponent = 0;
|
|
}
|
|
ShaderParameters.Color *= LightSceneInfo->Proxy->GetIndirectLightingScale();
|
|
// InverseExposureBlend applied in shader since it's view dependent
|
|
|
|
FDFVector3 WorldPositionDF { ShaderParameters.WorldPosition };
|
|
|
|
FLumenPackedLight& LightData = TaskData->PackedLightData[LightIndex];
|
|
LightData.WorldPositionHigh = WorldPositionDF.High;
|
|
LightData.LightingChannelMask = LightSceneInfo->Proxy->GetLightingChannelMask();
|
|
|
|
LightData.WorldPositionLow = WorldPositionDF.Low;
|
|
LightData.InvRadius = ShaderParameters.InvRadius;
|
|
|
|
LightData.Color = FVector3f(ShaderParameters.Color);
|
|
LightData.FalloffExponent = ShaderParameters.FalloffExponent;
|
|
|
|
LightData.Direction = ShaderParameters.Direction;
|
|
LightData.DiffuseAndSpecularScale = PackRG16(ShaderParameters.DiffuseScale, ShaderParameters.SpecularScale);
|
|
|
|
LightData.Tangent = ShaderParameters.Tangent;
|
|
LightData.SourceRadius = ShaderParameters.SourceRadius;
|
|
|
|
LightData.SpotAngles = ShaderParameters.SpotAngles;
|
|
LightData.SoftSourceRadius = ShaderParameters.SoftSourceRadius;
|
|
LightData.SourceLength = ShaderParameters.SourceLength;
|
|
|
|
LightData.RectLightBarnCosAngle = ShaderParameters.RectLightBarnCosAngle;
|
|
LightData.RectLightBarnLength = ShaderParameters.RectLightBarnLength;
|
|
LightData.RectLightAtlasMaxLevel = ShaderParameters.RectLightAtlasMaxLevel > 0.0f ? ShaderParameters.RectLightAtlasMaxLevel : 0.0f;
|
|
LightData.LightType = LightType;
|
|
|
|
if (LightData.LightType == LightType_Rect)
|
|
{
|
|
LightData.SinCosConeAngleOrRectLightAtlasUVScale = ShaderParameters.RectLightAtlasUVScale;
|
|
}
|
|
else
|
|
{
|
|
LightData.SinCosConeAngleOrRectLightAtlasUVScale = FVector2f(FMath::Sin(LightSceneInfo->Proxy->GetOuterConeAngle()), FMath::Cos(LightSceneInfo->Proxy->GetOuterConeAngle()));
|
|
}
|
|
LightData.RectLightAtlasUVOffset = ShaderParameters.RectLightAtlasUVOffset;
|
|
LightData.IESAtlasIndex = ShaderParameters.IESAtlasIndex;
|
|
LightData.LightFunctionAtlasIndex_bHasShadowMask_bIsStandalone_bCastDynamicShadows =
|
|
(ShaderParameters.LightFunctionAtlasLightIndex & 0x1FFFFFFFu) |
|
|
( LumenLight.NeedsShadowMask() ? (1 << 31) : 0) |
|
|
(!LumenLight.CanUseBatchedShadows() ? (1 << 30) : 0) |
|
|
(LumenLight.bHasShadows ? 1u << 29 : 0);
|
|
LightData.InverseExposureBlend = ShaderParameters.InverseExposureBlend;
|
|
LightData.Padding0 = 0;
|
|
|
|
if (bUseBatchedShadows && !bUseLightTilesPerLightType && LumenLight.NeedsShadowMask() && LumenLight.CanUseBatchedShadows())
|
|
{
|
|
for (int32 OriginIndex = 0; OriginIndex < NumViewOrigins; ++OriginIndex)
|
|
{
|
|
FPerLightParameters& LightParameters = TaskData->ViewBatchedLightParameters[OriginIndex].PerLightTypeParameters[(int32)LumenLight.Type].AddDefaulted_GetRef();
|
|
SetPerLightParameters(LightParameters, LumenLight, OriginIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DO_CHECK
|
|
for (FViewBatchedLightParameters& ViewLightParameters : TaskData->ViewBatchedLightParameters)
|
|
{
|
|
for (int32 LightTypeIndex = 0; LightTypeIndex < NumLightTypes; ++LightTypeIndex)
|
|
{
|
|
if (bUseLightTilesPerLightType)
|
|
{
|
|
check(ViewLightParameters.PerLightTypeParameters[LightTypeIndex].Num() == FMath::Min(BatchedLightCounts[LightTypeIndex], 1));
|
|
}
|
|
else
|
|
{
|
|
check(ViewLightParameters.PerLightTypeParameters[LightTypeIndex].Num() == BatchedLightCounts[LightTypeIndex]);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}, Prerequisites);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class FLumenSceneDirectLightingStatsCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FLumenSceneDirectLightingStatsCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FLumenSceneDirectLightingStatsCS, FGlobalShader)
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER(uint32, NumLights)
|
|
SHADER_PARAMETER(uint32, NumViews)
|
|
SHADER_PARAMETER(FIntPoint, AtlasResolution)
|
|
SHADER_PARAMETER(FIntPoint, UpdateAtlasSize)
|
|
SHADER_PARAMETER(uint32, MaxUpdateTiles)
|
|
SHADER_PARAMETER(uint32, UpdateFactor)
|
|
SHADER_PARAMETER(uint32, NumBatchedLights)
|
|
SHADER_PARAMETER(uint32, NumStandaloneLights)
|
|
SHADER_PARAMETER(uint32, bHasRectLights)
|
|
SHADER_PARAMETER(uint32, bHasLightFunctionLights)
|
|
SHADER_PARAMETER(uint32, bHasIESLights)
|
|
SHADER_PARAMETER(uint32, bHWRT)
|
|
SHADER_PARAMETER(uint32, bValidDebugData)
|
|
// Scene
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardPageIndexAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardPageIndexData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTileAllocator)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CardTiles)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FLumenCardScene, LumenCardScene)
|
|
// Debug
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DebugDataBuffer)
|
|
// Traces
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CompactedTraceAllocator)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintUniformBuffer)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
using FPermutationDomain = TShaderPermutationDomain<>;
|
|
|
|
static int32 GetGroupSize()
|
|
{
|
|
return 8;
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportLumenGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
|
|
OutEnvironment.SetDefine(TEXT("SHADER_DEBUG"), 1);
|
|
}
|
|
|
|
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return EShaderPermutationPrecacheRequest::NotPrecached;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FLumenSceneDirectLightingStatsCS, "/Engine/Private/Lumen/LumenSceneLightingDebug.usf", "LumenSceneDirectLightingStatsCS", SF_Compute);
|
|
|
|
static void AddLumenSceneDirectLightingStatsPass(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FScene* Scene,
|
|
const FViewInfo& View,
|
|
const FLumenSceneFrameTemporaries& FrameTemporaries,
|
|
const FLumenDirectLightingTaskData* LightingTaskData,
|
|
const FLumenCardUpdateContext& CardUpdateContext,
|
|
const FLumenCardTileUpdateContext& CardTileUpdateContext,
|
|
FRDGBufferRef CompactedTraceAllocator,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
ShaderPrint::SetEnabled(true);
|
|
ShaderPrint::RequestSpaceForCharacters(4096);
|
|
ShaderPrint::RequestSpaceForLines(CardUpdateContext.MaxUpdateTiles * 12u * 2u);
|
|
if (!ShaderPrint::IsEnabled(View.ShaderPrintData))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Trace view ray to get debug info
|
|
const bool bValidDebugData = FrameTemporaries.DebugData != nullptr;
|
|
FRDGBufferSRVRef DebugData = bValidDebugData ? FrameTemporaries.DebugData : GraphBuilder.CreateSRV(GSystemTextures.GetDefaultStructuredBuffer(GraphBuilder, 4, 0u));
|
|
|
|
FLumenSceneDirectLightingStatsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLumenSceneDirectLightingStatsCS::FParameters>();
|
|
PassParameters->NumLights = LightingTaskData->GatheredLights.Num();
|
|
PassParameters->NumViews = FrameTemporaries.ViewOrigins.Num();
|
|
PassParameters->AtlasResolution = FrameTemporaries.AlbedoAtlas->Desc.Extent;
|
|
PassParameters->UpdateAtlasSize = CardUpdateContext.UpdateAtlasSize;
|
|
PassParameters->MaxUpdateTiles = CardUpdateContext.MaxUpdateTiles;
|
|
PassParameters->UpdateFactor = CardUpdateContext.UpdateFactor;
|
|
PassParameters->bHWRT = Lumen::UseHardwareRayTracedDirectLighting(*View.Family) ? 1u : 0u;
|
|
|
|
PassParameters->NumBatchedLights = LightingTaskData->GatheredLights.Num() - LightingTaskData->StandaloneLightIndices.Num();
|
|
PassParameters->NumStandaloneLights = LightingTaskData->StandaloneLightIndices.Num();
|
|
PassParameters->bHasRectLights = LightingTaskData->bHasRectLights ? 1u : 0u;
|
|
PassParameters->bHasLightFunctionLights = LightingTaskData->bHasLightFunctions ? 1u : 0u;
|
|
PassParameters->bHasIESLights = LightingTaskData->bHasIESLights ? 1u : 0u;
|
|
PassParameters->CompactedTraceAllocator = GraphBuilder.CreateSRV(CompactedTraceAllocator);
|
|
PassParameters->DebugDataBuffer = DebugData;
|
|
PassParameters->bValidDebugData = bValidDebugData ? 1u : 0u;
|
|
|
|
PassParameters->LumenCardScene = FrameTemporaries.LumenCardSceneUniformBuffer;
|
|
PassParameters->CardPageIndexAllocator = GraphBuilder.CreateSRV(CardUpdateContext.CardPageIndexAllocator);
|
|
PassParameters->CardPageIndexData = GraphBuilder.CreateSRV(CardUpdateContext.CardPageIndexData);
|
|
|
|
PassParameters->CardTileAllocator = GraphBuilder.CreateSRV(CardTileUpdateContext.CardTileAllocator);
|
|
PassParameters->CardTiles = GraphBuilder.CreateSRV(CardTileUpdateContext.CardTiles);
|
|
|
|
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, PassParameters->ShaderPrintUniformBuffer);
|
|
|
|
FLumenSceneDirectLightingStatsCS::FPermutationDomain PermutationVector;
|
|
auto ComputeShader = View.ShaderMap->GetShader<FLumenSceneDirectLightingStatsCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("LumenScene::Debug"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(1,1,1));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Stochastic direct lighting
|
|
#include "LumenSceneDirectLightingStochastic.inl"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FDeferredShadingSceneRenderer::RenderDirectLightingForLumenScene(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FLumenSceneFrameTemporaries& FrameTemporaries,
|
|
const FLumenDirectLightingTaskData* LightingTaskData,
|
|
const FLumenCardUpdateContext& CardUpdateContext,
|
|
ERDGPassFlags ComputePassFlags)
|
|
{
|
|
LLM_SCOPE_BYTAG(Lumen);
|
|
|
|
if (LightingTaskData)
|
|
{
|
|
LightingTaskData->Task.Wait();
|
|
}
|
|
|
|
if (CVarLumenLumenSceneDirectLighting.GetValueOnRenderThread() != 0 && CardUpdateContext.MaxUpdateTiles > 0)
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "DirectLighting");
|
|
QUICK_SCOPE_CYCLE_COUNTER(RenderDirectLightingForLumenScene);
|
|
|
|
check(LightingTaskData);
|
|
const FViewInfo& MainView = Views[0];
|
|
FLumenSceneData& LumenSceneData = *Scene->GetLumenSceneData(Views[0]);
|
|
|
|
int32 NumViewOrigins = FrameTemporaries.ViewOrigins.Num();
|
|
|
|
TRDGUniformBufferRef<FLumenCardScene> LumenCardSceneUniformBuffer = FrameTemporaries.LumenCardSceneUniformBuffer;
|
|
|
|
TConstArrayView<FLumenGatheredLight> GatheredLights = LightingTaskData->GatheredLights;
|
|
const bool bHasRectLights = LightingTaskData->bHasRectLights;
|
|
|
|
FRDGBufferRef LumenPackedLights = CreateStructuredBuffer(GraphBuilder, TEXT("Lumen.DirectLighting.Lights"), LightingTaskData->PackedLightData, ERDGInitialDataFlags::NoCopy);
|
|
FRDGBufferRef LumenLightInfluenceSpheres = CreateStructuredBuffer(GraphBuilder, TEXT("Lumen.DirectLighting.LightInfluenceSpheres"), LightingTaskData->LightInfluenceSpheres, ERDGInitialDataFlags::NoCopy);
|
|
|
|
LumenSceneDirectLighting::FLightDataParameters LumenLightData;
|
|
LumenLightData.LumenPackedLights = GraphBuilder.CreateSRV(LumenPackedLights);
|
|
LumenLightData.LumenLightInfluenceSpheres = GraphBuilder.CreateSRV(LumenLightInfluenceSpheres);
|
|
|
|
const bool bUseHardwareRayTracedDirectLighting = Lumen::UseHardwareRayTracedDirectLighting(ViewFamily);
|
|
|
|
// Experimental Stochastic lighting path.
|
|
if (LumenSceneDirectLighting::UseStochasticLighting(ViewFamily))
|
|
{
|
|
ComputeStochasticLighting(GraphBuilder, Scene, Views[0], FrameTemporaries, LightingTaskData, CardUpdateContext, ComputePassFlags, LumenLightData);
|
|
return;
|
|
}
|
|
|
|
FLightTileCullContext CullContext;
|
|
FLumenCardTileUpdateContext CardTileUpdateContext;
|
|
CullDirectLightingTiles(GraphBuilder, Views, FrameTemporaries, CardUpdateContext, LumenCardSceneUniformBuffer, GatheredLights, LightingTaskData->StandaloneLightIndices, LumenLightData, CullContext, CardTileUpdateContext, ComputePassFlags);
|
|
|
|
// 8 bits per shadow mask texel. But if colored light function atlas is used, then 16bits per shadow mask texel.
|
|
const uint32 ShadowMaskTilesSizeFactor = GetLightFunctionAtlasFormat() > 0 ? 2 : 1;
|
|
const uint32 ShadowMaskTilesSize = FMath::Max(ShadowMaskTilesSizeFactor * 16 * CullContext.MaxCulledCardTiles, 1024u);
|
|
FRDGBufferRef ShadowMaskTiles = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), ShadowMaskTilesSize), TEXT("Lumen.DirectLighting.ShadowMaskTiles"));
|
|
|
|
// 1 uint per packed shadow trace
|
|
FRDGBufferRef ShadowTraceAllocator = nullptr;
|
|
FRDGBufferRef ShadowTraces = nullptr;
|
|
if (bUseHardwareRayTracedDirectLighting)
|
|
{
|
|
const uint32 MaxShadowTraces = FMath::Max(Lumen::CardTileSize * Lumen::CardTileSize * CullContext.MaxCulledCardTiles, 1024u);
|
|
|
|
ShadowTraceAllocator = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), 1), TEXT("Lumen.DirectLighting.ShadowTraceAllocator"));
|
|
ShadowTraces = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), MaxShadowTraces), TEXT("Lumen.DirectLighting.ShadowTraces"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(ShadowTraceAllocator), 0, ComputePassFlags);
|
|
}
|
|
|
|
// Compute shadow mask based on light attenuation (IES/LightFunction/Distance fall) to reduce need for shadow tracing done after.
|
|
{
|
|
SCOPED_NAMED_EVENT_TEXT("Light Attenuation ShadowMask ", FColor::Green);
|
|
RDG_EVENT_SCOPE_FINAL(GraphBuilder, "Light Attenuation ShadowMask");
|
|
|
|
FRDGBufferUAVRef ShadowMaskTilesUAV = GraphBuilder.CreateUAV(ShadowMaskTiles, ERDGUnorderedAccessViewFlags::SkipBarrier);
|
|
FRDGBufferUAVRef ShadowTraceAllocatorUAV = ShadowTraceAllocator ? GraphBuilder.CreateUAV(ShadowTraceAllocator, ERDGUnorderedAccessViewFlags::SkipBarrier) : nullptr;
|
|
FRDGBufferUAVRef ShadowTracesUAV = ShadowTraces ? GraphBuilder.CreateUAV(ShadowTraces, ERDGUnorderedAccessViewFlags::SkipBarrier) : nullptr;
|
|
FRDGBufferSRVRef TileShadowDownsampleFactorAtlasSRV = GraphBuilder.CreateSRV(FrameTemporaries.TileShadowDownsampleFactorAtlas, PF_R32_UINT);
|
|
|
|
int32 NumShadowedLights = 0;
|
|
for (int32 OriginIndex = 0; OriginIndex < NumViewOrigins; ++OriginIndex)
|
|
{
|
|
const FViewInfo& View = *FrameTemporaries.ViewOrigins[OriginIndex].ReferenceView;
|
|
|
|
NumShadowedLights = ComputeShadowMaskFromLightAttenuation(
|
|
GraphBuilder,
|
|
Scene,
|
|
View,
|
|
LumenCardSceneUniformBuffer,
|
|
GatheredLights,
|
|
LightingTaskData->StandaloneLightIndices,
|
|
LightingTaskData->ViewBatchedLightParameters[OriginIndex],
|
|
CullContext.LightTileScatterParameters,
|
|
LumenLightData,
|
|
OriginIndex,
|
|
NumViewOrigins,
|
|
LightingTaskData->bHasLightFunctions,
|
|
ShadowMaskTilesUAV,
|
|
ShadowTraceAllocatorUAV,
|
|
ShadowTracesUAV,
|
|
TileShadowDownsampleFactorAtlasSRV,
|
|
ComputePassFlags);
|
|
}
|
|
|
|
// Clear to mark resource as used if it wasn't ever written to
|
|
if (ShadowTracesUAV && NumShadowedLights == 0)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, ShadowTracesUAV, 0);
|
|
}
|
|
}
|
|
|
|
FRDGBufferRef ShadowTraceIndirectArgs = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(1), TEXT("Lumen.DirectLighting.CompactedShadowTraceIndirectArgs"));
|
|
if (ShadowTraceAllocator)
|
|
{
|
|
FInitShadowTraceIndirectArgsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FInitShadowTraceIndirectArgsCS::FParameters>();
|
|
PassParameters->RWShadowTraceIndirectArgs = GraphBuilder.CreateUAV(ShadowTraceIndirectArgs);
|
|
PassParameters->ShadowTraceAllocator = GraphBuilder.CreateSRV(ShadowTraceAllocator);
|
|
|
|
auto ComputeShader = Views[0].ShaderMap->GetShader<FInitShadowTraceIndirectArgsCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("InitShadowTraceIndirectArgs"),
|
|
ComputePassFlags,
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(1, 1, 1));
|
|
}
|
|
|
|
// Offscreen shadowing
|
|
{
|
|
SCOPED_NAMED_EVENT_TEXT("Offscreen shadows", FColor::Green);
|
|
RDG_EVENT_SCOPE_FINAL(GraphBuilder, "Offscreen shadows");
|
|
|
|
FRDGBufferUAVRef ShadowMaskTilesUAV = GraphBuilder.CreateUAV(ShadowMaskTiles, ERDGUnorderedAccessViewFlags::SkipBarrier);
|
|
|
|
FDistanceFieldObjectBufferParameters ObjectBufferParameters;
|
|
|
|
if (!bUseHardwareRayTracedDirectLighting)
|
|
{
|
|
ObjectBufferParameters = DistanceField::SetupObjectBufferParameters(GraphBuilder, Scene->DistanceFieldSceneData);
|
|
|
|
// Patch DF heightfields with Lumen heightfields
|
|
ObjectBufferParameters.SceneHeightfieldObjectBounds = GraphBuilder.CreateSRV(GraphBuilder.RegisterExternalBuffer(LumenSceneData.HeightfieldBuffer));
|
|
ObjectBufferParameters.SceneHeightfieldObjectData = nullptr;
|
|
ObjectBufferParameters.NumSceneHeightfieldObjects = LumenSceneData.Heightfields.Num();
|
|
}
|
|
|
|
for (int32 OriginIndex = 0; OriginIndex < NumViewOrigins; ++OriginIndex)
|
|
{
|
|
const FViewInfo& View = *FrameTemporaries.ViewOrigins[OriginIndex].ReferenceView;
|
|
|
|
if (bUseHardwareRayTracedDirectLighting)
|
|
{
|
|
FLumenDirectLightingStochasticData StochasticData;
|
|
TraceLumenHardwareRayTracedDirectLightingShadows(
|
|
GraphBuilder,
|
|
Scene,
|
|
View,
|
|
OriginIndex,
|
|
FrameTemporaries,
|
|
StochasticData,
|
|
LumenLightData,
|
|
ShadowTraceIndirectArgs,
|
|
ShadowTraceAllocator,
|
|
ShadowTraces,
|
|
CullContext.LightTileAllocator,
|
|
CullContext.LightTiles,
|
|
ShadowMaskTilesUAV,
|
|
ComputePassFlags);
|
|
}
|
|
else
|
|
{
|
|
TraceDistanceFieldShadows(
|
|
GraphBuilder,
|
|
Scene,
|
|
View,
|
|
LumenCardSceneUniformBuffer,
|
|
GatheredLights,
|
|
LightingTaskData->StandaloneLightIndices,
|
|
LightingTaskData->ViewBatchedLightParameters[OriginIndex],
|
|
CullContext.LightTileScatterParameters,
|
|
LumenLightData,
|
|
ObjectBufferParameters,
|
|
OriginIndex,
|
|
NumViewOrigins,
|
|
ShadowMaskTilesUAV,
|
|
ComputePassFlags);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply lights
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "Lights");
|
|
|
|
FRDGBufferSRVRef ShadowMaskTilesSRV = GraphBuilder.CreateSRV(ShadowMaskTiles->HasBeenProduced() ? ShadowMaskTiles : GSystemTextures.GetDefaultStructuredBuffer(GraphBuilder, sizeof(uint32)));
|
|
FRDGBufferSRVRef CardTilesSRV = GraphBuilder.CreateSRV(CardTileUpdateContext.CardTiles);
|
|
FRDGBufferSRVRef LightTileOffsetNumPerCardTileSRV = GraphBuilder.CreateSRV(CullContext.LightTileOffsetNumPerCardTile);
|
|
FRDGBufferSRVRef LightTilesPerCardTileSRV = GraphBuilder.CreateSRV(CullContext.LightTilesPerCardTile);
|
|
FRDGTextureUAVRef DirectLightingAtlasUAV = GraphBuilder.CreateUAV(FrameTemporaries.DirectLightingAtlas);
|
|
|
|
RenderDirectLightIntoLumenCardsBatched(
|
|
GraphBuilder,
|
|
Views,
|
|
FrameTemporaries,
|
|
LumenCardSceneUniformBuffer,
|
|
LumenLightData,
|
|
ShadowMaskTilesSRV,
|
|
CardTilesSRV,
|
|
LightTileOffsetNumPerCardTileSRV,
|
|
LightTilesPerCardTileSRV,
|
|
DirectLightingAtlasUAV,
|
|
CardTileUpdateContext.DispatchCardTilesIndirectArgs,
|
|
bHasRectLights,
|
|
ComputePassFlags);
|
|
}
|
|
|
|
// Update Final Lighting
|
|
Lumen::CombineLumenSceneLighting(
|
|
Scene,
|
|
MainView,
|
|
GraphBuilder,
|
|
FrameTemporaries,
|
|
CardUpdateContext,
|
|
CardTileUpdateContext,
|
|
ComputePassFlags);
|
|
|
|
// Draw direct lighting stats & Lumen cards/tiles
|
|
if (GetLumenLightingStatMode() == 3)
|
|
{
|
|
AddLumenSceneDirectLightingStatsPass(
|
|
GraphBuilder,
|
|
Scene,
|
|
MainView,
|
|
FrameTemporaries,
|
|
LightingTaskData,
|
|
CardUpdateContext,
|
|
CardTileUpdateContext,
|
|
ShadowTraceAllocator,
|
|
ComputePassFlags);
|
|
}
|
|
}
|
|
else if (CVarLumenLumenSceneDirectLighting.GetValueOnRenderThread() == 0)
|
|
{
|
|
AddClearRenderTargetPass(GraphBuilder, FrameTemporaries.DirectLightingAtlas);
|
|
}
|
|
}
|