Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/MegaLights/MegaLights.cpp
2025-05-18 13:04:45 +08:00

3026 lines
141 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MegaLights.h"
#include "MegaLightsDefinitions.h"
#include "MegaLightsInternal.h"
#include "RendererPrivate.h"
#include "PixelShaderUtils.h"
#include "BasePassRendering.h"
#include "VolumetricFogShared.h"
#include "Shadows/ShadowSceneRenderer.h"
#include "HairStrands/HairStrandsData.h"
static TAutoConsoleVariable<int32> CVarMegaLightsProjectSetting(
TEXT("r.MegaLights.EnableForProject"),
0,
TEXT("Whether to use MegaLights by default, but this can still be overridden by Post Process Volumes, or disabled per-light. MegaLights uses stochastic sampling to render many shadow casting lights efficiently, with a consistent low GPU cost. MegaLights requires Hardware Ray Tracing, and does not support Directional Lights. Experimental feature."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsAllowed(
TEXT("r.MegaLights.Allowed"),
1,
TEXT("Whether the MegaLights feature is allowed by scalability and device profiles."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDownsampleFactor(
TEXT("r.MegaLights.DownsampleFactor"),
2,
TEXT("Downsample factor from the main viewport to trace rays."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsNumSamplesPerPixel(
TEXT("r.MegaLights.NumSamplesPerPixel"),
4,
TEXT("Number of samples per pixel. Supported values: 2, 4 and 16."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsMinSampleWeight(
TEXT("r.MegaLights.MinSampleWeight"),
0.001f,
TEXT("Determines minimal sample influence on final pixels. Used to skip samples which would have minimal impact to the final image even if light is fully visible."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsMaxShadingWeight(
TEXT("r.MegaLights.MaxShadingWeight"),
20.0f,
TEXT("Clamps low-probability samples in order to reduce fireflies."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsGuideByHistory(
TEXT("r.MegaLights.GuideByHistory"),
2,
TEXT("Whether to reduce sampling chance for lights which were hidden last frame. Reduces noise in areas where bright lights are shadowed.\n")
TEXT("0 - disabled\n")
TEXT("1 - more rays towards visible lights\n")
TEXT("2 - more rays towards visible parts of lights"),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsGuideByHistoryVisibleSamplePercentage(
TEXT("r.MegaLights.GuideByHistory.VisibleSamplePercentage"),
0.8f,
TEXT("Percentage of samples which should be used to sample visible lights. Higher values reduce noise, but are slower to discover new visible lights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsGuideByHistoryFilter(
TEXT("r.MegaLights.GuideByHistory.Filter"),
1,
TEXT("Whether to filter history by sharing visibility between nearby tiles."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsGuideByHistoryAreaLightHiddenWeight(
TEXT("r.MegaLights.GuideByHistory.AreaLightHiddenWeight"),
0.25f,
TEXT("PDF weight for hidden parts of an area light. 1 will disable area light guiding. Lower values will improve static quality, but will cause more artifacts in motion when area light guiding is wrong."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsShadingConfidence(
TEXT("r.MegaLights.ShadingConfidence"),
1,
TEXT("Whether to use shading confidence to reduce denoising and passthrough original signal to TSR for pixels which are well sampled."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTemporal(
TEXT("r.MegaLights.Temporal"),
1,
TEXT("Whether to use temporal accumulation for shadow mask."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTemporalMinFramesAccumulatedForHistoryMiss(
TEXT("r.MegaLights.Temporal.MinFramesAccumulatedForHistoryMiss"),
4,
TEXT("Minimal amount of history length when reducing history length due to a history miss. Higher values than 1 soften and slowdown transitions."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTemporalMinFramesAccumulatedForHighConfidence(
TEXT("r.MegaLights.Temporal.MinFramesAccumulatedForHighConfidence"),
2,
TEXT("Minimal amount of history length when reducing history length due to a high confidence. Higher values than 1 soften image, but reduce noise in high confidence areas."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTemporalMaxFramesAccumulated(
TEXT("r.MegaLights.Temporal.MaxFramesAccumulated"),
12,
TEXT("Max history length when accumulating frames. Lower values have less ghosting, but more noise."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsTemporalNeighborhoodClampScale(
TEXT("r.MegaLights.Temporal.NeighborhoodClampScale"),
1.0f,
TEXT("Scales how permissive is neighborhood clamp. Higher values increase ghosting, but reduce noise and instability."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsSpatial(
TEXT("r.MegaLights.Spatial"),
1,
TEXT("Whether denoiser should run spatial filter."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsSpatialDepthWeightScale(
TEXT("r.MegaLights.Spatial.DepthWeightScale"),
10000.0f,
TEXT("Scales the depth weight of the spatial filter. Smaller values allow for more sample reuse, but also introduce more bluriness between unrelated surfaces."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsSpatialKernelRadius(
TEXT("r.MegaLights.Spatial.KernelRadius"),
8.0f,
TEXT("Spatial filter kernel radius in pixels"),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsSpatialNumSamples(
TEXT("r.MegaLights.Spatial.NumSamples"),
4,
TEXT("Number of spatial filter samples."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsSpatialMaxDisocclusionFrames(
TEXT("r.MegaLights.Spatial.MaxDisocclusionFrames"),
3,
TEXT("Number of of history frames to boost spatial filtering in order to minimize noise after disocclusion."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsWaveOps(
TEXT("r.MegaLights.WaveOps"),
1,
TEXT("Whether to use wave ops. Useful for debugging."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDebug(
TEXT("r.MegaLights.Debug"),
0,
TEXT("Whether to enabled debug mode, which prints various extra debug information from shaders.")
TEXT("0 - Disable\n")
TEXT("1 - Visualize tracing\n")
TEXT("2 - Visualize sampling"),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDebugCursorX(
TEXT("r.MegaLights.Debug.CursorX"),
-1,
TEXT("Override default debug visualization cursor position."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDebugCursorY(
TEXT("r.MegaLights.Debug.CursorY"),
-1,
TEXT("Override default debug visualization cursor position."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDebugLightId(
TEXT("r.MegaLights.Debug.LightId"),
-1,
TEXT("Which light to show debug info for. When set to -1, uses the currently selected light in editor."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDebugVisualizeLight(
TEXT("r.MegaLights.Debug.VisualizeLight"),
0,
TEXT("Whether to visualize selected light. Useful to find in in the level."),
ECVF_RenderThreadSafe
);
int32 GMegaLightsReset = 0;
FAutoConsoleVariableRef CVarMegaLightsReset(
TEXT("r.MegaLights.Reset"),
GMegaLightsReset,
TEXT("Reset history for debugging."),
ECVF_RenderThreadSafe
);
int32 GMegaLightsResetEveryNthFrame = 0;
FAutoConsoleVariableRef CVarMegaLightsResetEveryNthFrame(
TEXT("r.MegaLights.ResetEveryNthFrame"),
GMegaLightsResetEveryNthFrame,
TEXT("Reset history every Nth frame for debugging."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsFixedStateFrameIndex(
TEXT("r.MegaLights.FixedStateFrameIndex"),
-1,
TEXT("Whether to override View.StateFrameIndex for debugging."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTexturedRectLights(
TEXT("r.MegaLights.TexturedRectLights"),
1,
TEXT("Whether to support textured rect lights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsLightFunctions(
TEXT("r.MegaLights.LightFunctions"),
1,
TEXT("Whether to support light functions."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<bool> CVarMegaLightLightingChannels(
TEXT("r.MegaLights.LightingChannels"),
1,
TEXT("Whether to enable lighting channels to block shadowing"),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsIESProfiles(
TEXT("r.MegaLights.IESProfiles"),
1,
TEXT("Whether to support IES profiles on lights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDirectionalLights(
TEXT("r.MegaLights.DirectionalLights"),
0,
TEXT("Whether to support directional lights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolume(
TEXT("r.MegaLights.Volume"),
1,
TEXT("Whether to enable a translucency volume used for Volumetric Fog and Volume Lit Translucency."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeDownsampleFactor(
TEXT("r.MegaLights.Volume.DownsampleFactor"),
2,
TEXT("Downsample factor applied to Volumetric Fog resolution. Affects the resolution at which rays are traced."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeHZBOcclusionTest(
TEXT("r.MegaLights.Volume.HZBOcclusionTest"),
1,
TEXT("Whether to skip computation for cells occluded by HZB."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeNumSamplesPerVoxel(
TEXT("r.MegaLights.Volume.NumSamplesPerVoxel"),
2,
TEXT("Number of samples (shadow rays) per half-res voxel. Supported values: 2 and 4."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsVolumeMinSampleWeight(
TEXT("r.MegaLights.Volume.MinSampleWeight"),
0.1f,
TEXT("Determines minimal sample influence on lighting cached in a volume. Used to skip samples which would have minimal impact to the final image even if light is fully visible."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsVolumeMaxShadingWeight(
TEXT("r.MegaLights.Volume.MaxShadingWeight"),
20.0f,
TEXT("Clamps low-probability samples in order to reduce fireflies."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeLightFunctions(
TEXT("r.MegaLights.Volume.LightFunctions"),
1,
TEXT("Whether to support light functions inside the mega light translucency volume."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeGuideByHistory(
TEXT("r.MegaLights.Volume.GuideByHistory"),
1,
TEXT("Whether to reduce sampling chance for lights which were hidden last frame. Reduces noise in areas where bright lights are shadowed.\n")
TEXT("0 - disabled\n")
TEXT("1 - more rays towards visible lights"),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsVolumeGuideByHistoryVisibleSamplePercentage(
TEXT("r.MegaLights.Volume.GuideByHistory.VisibleSamplePercentage"),
0.8f,
TEXT("Percentage of samples which should be used to sample visible lights. Higher values reduce noise, but are slower to discover new visible lights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeGuideByHistoryFilter(
TEXT("r.MegaLights.Volume.GuideByHistory.Filter"),
1,
TEXT("Whether to filter history by sharing visibility between nearby voxels."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeDebug(
TEXT("r.MegaLights.Volume.Debug"),
0,
TEXT("Whether to enabled debug mode, which prints various extra debug information from volume shaders.")
TEXT("0 - Disable\n")
TEXT("1 - Visualize tracing\n")
TEXT("2 - Visualize sampling"),
ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarMegaLightsVolumeDebugSliceIndex(
TEXT("r.MegaLights.Volume.DebugSliceIndex"),
16,
TEXT("Which volume slice to visualize."),
ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolume(
TEXT("r.MegaLights.TranslucencyVolume"),
1,
TEXT("Whether to enable Lit Translucency Volume."),
ECVF_Scalability | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolumeDownsampleFactor(
TEXT("r.MegaLights.TranslucencyVolume.DownsampleFactor"),
2,
TEXT("Downsample factor applied to Translucency Lighting Volume resolution. Affects the resolution at which rays are traced."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolumeNumSamplesPerVoxel(
TEXT("r.MegaLights.TranslucencyVolume.NumSamplesPerVoxel"),
2,
TEXT("Number of samples (shadow rays) per half-res voxel. Supported values: 2 and 4."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsTranslucencyVolumeMinSampleWeight(
TEXT("r.MegaLights.TranslucencyVolume.MinSampleWeight"),
0.1f,
TEXT("Determines minimal sample influence on lighting cached in a volume. Used to skip samples which would have minimal impact to the final image even if light is fully visible."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsTranslucencyVolumeMaxShadingWeight(
TEXT("r.MegaLights.TranslucencyVolume.MaxShadingWeight"),
20.0f,
TEXT("Clamps low-probability samples in order to reduce fireflies."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolumeLightFunctions(
TEXT("r.MegaLights.TranslucencyVolume.LightFunctions"),
1,
TEXT("Whether to support light functions inside the mega light translucency volume."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolumeGuideByHistory(
TEXT("r.MegaLights.TranslucencyVolume.GuideByHistory"),
1,
TEXT("Whether to reduce sampling chance for lights which were hidden last frame. Reduces noise in areas where bright lights are shadowed.\n")
TEXT("0 - disabled\n")
TEXT("1 - more rays towards visible lights"),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<float> CVarMegaLightsTranslucencyVolumeGuideByHistoryVisibleSamplePercentage(
TEXT("r.MegaLights.TranslucencyVolume.GuideByHistory.VisibleSamplePercentage"),
0.8f,
TEXT("Percentage of samples which should be used to sample visible lights. Higher values reduce noise, but are slower to discover new visible lights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolumeGuideByHistoryFilter(
TEXT("r.MegaLights.TranslucencyVolume.GuideByHistory.Filter"),
1,
TEXT("Whether to filter history by sharing visibility between nearby voxels."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsTranslucencyVolumeDebug(
TEXT("r.MegaLights.TranslucencyVolume.Debug"),
0,
TEXT("Whether to enabled debug mode, which prints various extra debug information from Translucency Volume shaders.")
TEXT("0 - Disable\n")
TEXT("1 - Visualize tracing\n")
TEXT("2 - Visualize sampling"),
ECVF_RenderThreadSafe);
// Rendering project setting
int32 GMegaLightsDefaultShadowMethod = 0;
FAutoConsoleVariableRef CMegaLightsDefaultShadowMethod(
TEXT("r.MegaLights.DefaultShadowMethod"),
GMegaLightsDefaultShadowMethod,
TEXT("The default shadowing method for MegaLights, unless over-ridden on the light component.\n")
TEXT("0 - Ray Tracing. Preferred method, which guarantees fixed MegaLights cost and correct area shadows, but is dependent on the BVH representation quality.\n")
TEXT("1 - Virtual Shadow Maps. Has a significant per light cost, but can cast shadows directly from the Nanite geometry using rasterization."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsEnableHairStrands(
TEXT("r.MegaLights.HairStrands"),
1,
TEXT("Wheter to enable hair strands support for MegaLights."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDownsampleFactorHairStrands(
TEXT("r.MegaLights.HairStrands.DownsampleFactor"),
1,
TEXT("Downsample factor from the main viewport to trace rays with hair strands."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsNumSamplesPerPixelHairStrands(
TEXT("r.MegaLights.HairStrands.NumSamplesPerPixel"),
4,
TEXT("Number of samples per pixel with hair strands. Supported values: 2, 4 and 16."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarMegaLightsDebugHairStrands(
TEXT("r.MegaLights.HairStrands.Debug"),
0,
TEXT("Whether to enabled debug mode for hairstrands, which prints various extra debug information from shaders.")
TEXT("0 - Disable\n")
TEXT("1 - Visualize tracing\n")
TEXT("2 - Visualize sampling"),
ECVF_RenderThreadSafe
);
namespace MegaLights
{
constexpr int32 TileSize = TILE_SIZE;
constexpr int32 VisibleLightHashSize = VISIBLE_LIGHT_HASH_SIZE;
bool ShouldCompileShaders(EShaderPlatform ShaderPlatform)
{
if (IsMobilePlatform(ShaderPlatform))
{
return false;
}
// SM6 because it uses typed loads to accumulate lights
return IsFeatureLevelSupported(ShaderPlatform, ERHIFeatureLevel::SM6) && RHISupportsWaveOperations(ShaderPlatform);
}
bool IsRequested(const FSceneViewFamily& ViewFamily)
{
return ViewFamily.Views[0]->FinalPostProcessSettings.bMegaLights
&& CVarMegaLightsAllowed.GetValueOnRenderThread() != 0
&& ViewFamily.EngineShowFlags.MegaLights
&& ShouldCompileShaders(ViewFamily.GetShaderPlatform());
}
bool HasRequiredTracingData(const FSceneViewFamily& ViewFamily)
{
return IsHardwareRayTracingSupported(ViewFamily) || IsSoftwareRayTracingSupported(ViewFamily);
}
bool IsEnabled(const FSceneViewFamily& ViewFamily)
{
return IsRequested(ViewFamily) && HasRequiredTracingData(ViewFamily);
}
uint32 GetSampleMargin()
{
// #ml_todo: should be calculated based on DownsampleFactor / Volume.DownsampleFactor
return 3;
}
bool UseVolume()
{
return CVarMegaLightsVolume.GetValueOnRenderThread() != 0;
}
bool UseTranslucencyVolume()
{
return CVarMegaLightsTranslucencyVolume.GetValueOnRenderThread() != 0;
}
bool IsUsingLightFunctions(const FSceneViewFamily& ViewFamily)
{
return IsEnabled(ViewFamily) && CVarMegaLightsLightFunctions.GetValueOnRenderThread() != 0;
}
bool IsUsingLightingChannels()
{
return CVarMegaLightLightingChannels.GetValueOnRenderThread() != 0;
}
EMegaLightsMode GetMegaLightsMode(const FSceneViewFamily& ViewFamily, uint8 LightType, bool bLightAllowsMegaLights, TEnumAsByte<EMegaLightsShadowMethod::Type> ShadowMethod)
{
if ((LightType != LightType_Directional || CVarMegaLightsDirectionalLights.GetValueOnRenderThread())
&& IsEnabled(ViewFamily)
&& bLightAllowsMegaLights)
{
// Resolve default
if (ShadowMethod == EMegaLightsShadowMethod::Default)
{
if (GMegaLightsDefaultShadowMethod == 1)
{
ShadowMethod = EMegaLightsShadowMethod::VirtualShadowMap;
}
else
{
ShadowMethod = EMegaLightsShadowMethod::RayTracing;
}
}
const bool bUseVSM = ShadowMethod == EMegaLightsShadowMethod::VirtualShadowMap;
if (bUseVSM)
{
return EMegaLightsMode::EnabledVSM;
}
// Just check first view, assuming the ray tracing flag is the same for all views. See comment in the ShouldRenderRayTracingEffect function that accepts a ViewFamily.
else if (ViewFamily.Views[0]->IsRayTracingAllowedForView())
{
return EMegaLightsMode::EnabledRT;
}
}
return EMegaLightsMode::Disabled;
}
uint32 GetStateFrameIndex(FSceneViewState* ViewState)
{
uint32 StateFrameIndex = ViewState ? ViewState->GetFrameIndex() : 0;
if (CVarMegaLightsFixedStateFrameIndex.GetValueOnRenderThread() >= 0)
{
StateFrameIndex = CVarMegaLightsFixedStateFrameIndex.GetValueOnRenderThread();
}
return StateFrameIndex;
}
uint32 GetDownsampleFactor(EMegaLightsInput InputType)
{
switch (InputType)
{
case EMegaLightsInput::GBuffer: return FMath::Clamp(CVarMegaLightsDownsampleFactor.GetValueOnAnyThread(), 1, 2);
case EMegaLightsInput::HairStrands: return FMath::Clamp(CVarMegaLightsDownsampleFactorHairStrands.GetValueOnAnyThread(), 1, 2);
default: checkf(false, TEXT("MegaLight::GetDownsampleFactor not implemented")); return 1;
};
}
FIntPoint GetNumSamplesPerPixel2d(int32 NumSamplesPerPixel1d)
{
if (NumSamplesPerPixel1d >= 16)
{
return FIntPoint(4, 4);
}
else if (NumSamplesPerPixel1d >= 4)
{
return FIntPoint(2, 2);
}
else
{
return FIntPoint(2, 1);
}
}
FIntPoint GetNumSamplesPerPixel2d(EMegaLightsInput InputType)
{
switch (InputType)
{
case EMegaLightsInput::GBuffer: return GetNumSamplesPerPixel2d(CVarMegaLightsNumSamplesPerPixel.GetValueOnAnyThread());
case EMegaLightsInput::HairStrands: return GetNumSamplesPerPixel2d(CVarMegaLightsNumSamplesPerPixelHairStrands.GetValueOnAnyThread());
default: checkf(false, TEXT("MegaLight::GetNumSamplesPerPixel2d not implemented")); return false;
};
}
FIntVector GetNumSamplesPerVoxel3d(int32 NumSamplesPerVoxel1d)
{
if (NumSamplesPerVoxel1d >= 4)
{
return FIntVector(2, 2, 1);
}
else
{
return FIntVector(2, 1, 1);
}
}
int32 GetDebugMode(EMegaLightsInput InputType)
{
if (CVarMegaLightsVolumeDebug.GetValueOnRenderThread() != 0 || CVarMegaLightsTranslucencyVolumeDebug.GetValueOnRenderThread() != 0)
{
return 0;
}
switch (InputType)
{
case EMegaLightsInput::GBuffer: return CVarMegaLightsDebug.GetValueOnRenderThread();
case EMegaLightsInput::HairStrands: return CVarMegaLightsDebugHairStrands.GetValueOnRenderThread();
};
return 0;
}
bool SupportsGuideByHistory(EMegaLightsInput InputType)
{
switch (InputType)
{
case EMegaLightsInput::GBuffer: return true;
case EMegaLightsInput::HairStrands: return false;
default: checkf(false, TEXT("MegaLight::SupportsGuideByHistory not implemented")); return false;
};
}
bool SupportsSpatialFilter(EMegaLightsInput InputType)
{
switch (InputType)
{
case EMegaLightsInput::GBuffer: return true;
case EMegaLightsInput::HairStrands: return false; // Disable for now due to lack of proper reconstruction filter
default: checkf(false, TEXT("MegaLight::SupportsSpatialFilter not implemented")); return false;
};
}
bool SupportsTemporalFilter(EMegaLightsInput InputType)
{
switch (InputType)
{
case EMegaLightsInput::GBuffer: return true;
case EMegaLightsInput::HairStrands: return false; // Disable for now due to lack of proper temporal reprojection
default: checkf(false, TEXT("MegaLight::SupportsTemporalFilter not implemented")); return false;
};
}
bool UseWaveOps(EShaderPlatform ShaderPlatform)
{
return CVarMegaLightsWaveOps.GetValueOnRenderThread() != 0
&& GRHISupportsWaveOperations
&& RHISupportsWaveOperations(ShaderPlatform);
}
void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FForwardLightingParameters::ModifyCompilationEnvironment(Platform, OutEnvironment);
ShaderPrint::ModifyCompilationEnvironment(Platform, OutEnvironment);
OutEnvironment.CompilerFlags.Add(CFLAG_WarningsAsErrors);
}
// Keep in sync with TILE_TYPE_* in shaders
enum class ETileType : uint8
{
SimpleShading = TILE_MODE_SIMPLE_SHADING,
ComplexShading = TILE_MODE_COMPLEX_SHADING,
SimpleShading_Rect = TILE_MODE_SIMPLE_SHADING_RECT,
ComplexShading_Rect = TILE_MODE_COMPLEX_SHADING_RECT,
SimpleShading_Rect_Textured = TILE_MODE_SIMPLE_SHADING_RECT_TEXTURED,
ComplexShading_Rect_Textured = TILE_MODE_COMPLEX_SHADING_RECT_TEXTURED,
SHADING_MAX_LEGACY = TILE_MODE_EMPTY,
Empty = TILE_MODE_EMPTY,
MAX_LEGACY = TILE_MODE_MAX_LEGACY,
SHADING_MIN_SUBSTRATE = TILE_MODE_SINGLE_SHADING,
SingleShading = TILE_MODE_SINGLE_SHADING,
ComplexSpecialShading = TILE_MODE_COMPLEX_SPECIAL_SHADING,
SingleShading_Rect = TILE_MODE_SINGLE_SHADING_RECT,
ComplexSpecialShading_Rect = TILE_MODE_COMPLEX_SPECIAL_SHADING_RECT,
SingleShading_Rect_Textured = TILE_MODE_SINGLE_SHADING_RECT_TEXTURED,
ComplexSpecialShading_Rect_Textured = TILE_MODE_COMPLEX_SPECIAL_SHADING_RECT_TEXTURED,
SHADING_MAX_SUBSTRATE = TILE_MODE_MAX,
MAX_SUBSTRATE = TILE_MODE_MAX
};
const TCHAR* GetTileTypeString(ETileType TileType)
{
switch (TileType)
{
case ETileType::SimpleShading: return TEXT("Simple");
case ETileType::SingleShading: return TEXT("Single");
case ETileType::ComplexShading: return TEXT("Complex");
case ETileType::ComplexSpecialShading: return TEXT("Complex Special ");
case ETileType::SimpleShading_Rect: return TEXT("Simple Rect");
case ETileType::SingleShading_Rect: return TEXT("Single Rect");
case ETileType::ComplexShading_Rect: return TEXT("Complex Rect");
case ETileType::ComplexSpecialShading_Rect: return TEXT("Complex Special Rect");
case ETileType::SimpleShading_Rect_Textured: return TEXT("Simple Textured Rect");
case ETileType::SingleShading_Rect_Textured: return TEXT("Single Textured Rect");
case ETileType::ComplexShading_Rect_Textured: return TEXT("Complex Textured Rect");
case ETileType::ComplexSpecialShading_Rect_Textured:return TEXT("Complex Special Textured Rect");
case ETileType::Empty: return TEXT("Empty");
default:
return nullptr;
}
}
bool IsRectLightTileType(ETileType TileType)
{
return TileType == MegaLights::ETileType::SimpleShading_Rect
|| TileType == MegaLights::ETileType::ComplexShading_Rect
|| TileType == MegaLights::ETileType::SimpleShading_Rect_Textured
|| TileType == MegaLights::ETileType::ComplexShading_Rect_Textured
|| TileType == MegaLights::ETileType::SingleShading_Rect
|| TileType == MegaLights::ETileType::ComplexSpecialShading_Rect
|| TileType == MegaLights::ETileType::SingleShading_Rect_Textured
|| TileType == MegaLights::ETileType::ComplexSpecialShading_Rect_Textured;
}
bool IsTexturedLightTileType(ETileType TileType)
{
return TileType == MegaLights::ETileType::SimpleShading_Rect_Textured
|| TileType == MegaLights::ETileType::ComplexShading_Rect_Textured
|| TileType == MegaLights::ETileType::SingleShading_Rect_Textured
|| TileType == MegaLights::ETileType::ComplexSpecialShading_Rect_Textured;
}
float GetTemporalMaxFramesAccumulated()
{
return FMath::Max(CVarMegaLightsTemporalMaxFramesAccumulated.GetValueOnRenderThread(), 1.0f);
}
float GetSpatialFilterMaxDisocclusionFrames()
{
return FMath::Max(FMath::Min(CVarMegaLightsSpatialMaxDisocclusionFrames.GetValueOnRenderThread(), GetTemporalMaxFramesAccumulated() - 1.0f), 0.0f);
}
TArray<int32> GetShadingTileTypes(EMegaLightsInput InputType)
{
// Build available tile types
TArray<int32> Out;
if (InputType == EMegaLightsInput::GBuffer)
{
for (int32 TileType = 0; TileType < (int32)MegaLights::ETileType::SHADING_MAX_LEGACY; ++TileType)
{
Out.Add(TileType);
}
if (Substrate::IsSubstrateEnabled())
{
for (int32 TileType = (int32)MegaLights::ETileType::SHADING_MIN_SUBSTRATE; TileType < (int32)MegaLights::ETileType::SHADING_MAX_SUBSTRATE; ++TileType)
{
Out.Add(TileType);
}
}
}
else if (InputType == EMegaLightsInput::HairStrands)
{
// Hair only uses complex tiles
Out.Add(int32(MegaLights::ETileType::ComplexShading));
Out.Add(int32(MegaLights::ETileType::ComplexShading_Rect));
Out.Add(int32(MegaLights::ETileType::ComplexShading_Rect_Textured));
}
return Out;
}
float GetGuideByHistoryHiddenRatio(float VisibleSamplePercentage)
{
VisibleSamplePercentage = FMath::Clamp(VisibleSamplePercentage, 0.0f, 1.0f);
if (VisibleSamplePercentage > 0.0f)
{
return (1 - VisibleSamplePercentage) / VisibleSamplePercentage;
}
else
{
return 0.0f;
}
}
float GetGuideByHistoryHiddenRatio()
{
return GetGuideByHistoryHiddenRatio(CVarMegaLightsGuideByHistoryVisibleSamplePercentage.GetValueOnRenderThread());
}
};
namespace MegaLightsVolume
{
uint32 GetDownsampleFactor()
{
return FMath::Clamp(CVarMegaLightsVolumeDownsampleFactor.GetValueOnAnyThread(), 1, 2);
}
FIntVector GetNumSamplesPerVoxel3d()
{
return MegaLights::GetNumSamplesPerVoxel3d(CVarMegaLightsVolumeNumSamplesPerVoxel.GetValueOnAnyThread());
}
bool UsesLightFunction()
{
return CVarMegaLightsVolumeLightFunctions.GetValueOnRenderThread() != 0;
}
float GetGuideByHistoryHiddenRatio()
{
return MegaLights::GetGuideByHistoryHiddenRatio(CVarMegaLightsVolumeGuideByHistoryVisibleSamplePercentage.GetValueOnRenderThread());
}
int32 GetDebugMode()
{
return CVarMegaLightsVolumeDebug.GetValueOnRenderThread();
}
}
namespace MegaLightsTranslucencyVolume
{
uint32 GetDownsampleFactor()
{
return FMath::Clamp(CVarMegaLightsTranslucencyVolumeDownsampleFactor.GetValueOnAnyThread(), 1, 2);
}
FIntVector GetNumSamplesPerVoxel3d()
{
return MegaLights::GetNumSamplesPerVoxel3d(CVarMegaLightsTranslucencyVolumeNumSamplesPerVoxel.GetValueOnAnyThread());
}
bool UsesLightFunction()
{
return CVarMegaLightsTranslucencyVolumeLightFunctions.GetValueOnRenderThread() != 0;
}
float GetGuideByHistoryHiddenRatio()
{
return MegaLights::GetGuideByHistoryHiddenRatio(CVarMegaLightsTranslucencyVolumeGuideByHistoryVisibleSamplePercentage.GetValueOnRenderThread());
}
int32 GetDebugMode()
{
return CVarMegaLightsTranslucencyVolumeDebug.GetValueOnRenderThread();
}
}
class FTileClassificationCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FTileClassificationCS)
SHADER_USE_PARAMETER_STRUCT(FTileClassificationCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWTileAllocator)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWTileData)
SHADER_PARAMETER(uint32, EnableTexturedRectLights)
END_SHADER_PARAMETER_STRUCT()
class FDownsampledClassification : SHADER_PERMUTATION_BOOL("DOWNSAMPLED_CLASSIFICATION");
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
class FInputType : SHADER_PERMUTATION_INT("INPUT_TYPE", int32(EMegaLightsInput::Count));
using FPermutationDomain = TShaderPermutationDomain<FDownsampledClassification, FDebugMode, FInputType>;
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
}
};
IMPLEMENT_GLOBAL_SHADER(FTileClassificationCS, "/Engine/Private/MegaLights/MegaLights.usf", "TileClassificationCS", SF_Compute);
class FInitTileIndirectArgsCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FInitTileIndirectArgsCS)
SHADER_USE_PARAMETER_STRUCT(FInitTileIndirectArgsCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWTileIndirectArgs)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWDownsampledTileIndirectArgs)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, TileAllocator)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DownsampledTileAllocator)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(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(FInitTileIndirectArgsCS, "/Engine/Private/MegaLights/MegaLights.usf", "InitTileIndirectArgsCS", SF_Compute);
class FGenerateLightSamplesCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FGenerateLightSamplesCS)
SHADER_USE_PARAMETER_STRUCT(FGenerateLightSamplesCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RDG_BUFFER_ACCESS(IndirectArgs, ERHIAccess::IndirectArgs)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float>, RWDownsampledSceneDepth)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<UNORM float3>, RWDownsampledSceneWorldNormal)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, RWLightSamples)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, RWLightSampleRays)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DownsampledTileAllocator)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DownsampledTileData)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, VisibleLightHashHistory)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, VisibleLightMaskHashHistory)
SHADER_PARAMETER(uint32, GuideByHistoryMode)
SHADER_PARAMETER(float, AreaLightHiddenPDFWeight)
SHADER_PARAMETER(float, GuideByHistoryHiddenRatio)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, ShadowMaskBits)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, MegaLightsDepthHistory)
SHADER_PARAMETER(FVector4f, HistoryScreenPositionScaleBias)
SHADER_PARAMETER(FVector4f, HistoryUVMinMax)
SHADER_PARAMETER(FVector4f, HistoryGatherUVMinMax)
SHADER_PARAMETER(FVector4f, HistoryBufferSizeAndInvSize)
SHADER_PARAMETER(FIntPoint, HistoryVisibleLightHashViewMinInTiles)
SHADER_PARAMETER(FIntPoint, HistoryVisibleLightHashViewSizeInTiles)
END_SHADER_PARAMETER_STRUCT()
class FTileType : SHADER_PERMUTATION_INT("TILE_TYPE", (int32)MegaLights::ETileType::SHADING_MAX_SUBSTRATE);
class FNumSamplesPerPixel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_PIXEL_1D", 2, 4, 16);
class FGuideByHistory : SHADER_PERMUTATION_BOOL("GUIDE_BY_HISTORY");
class FInputType : SHADER_PERMUTATION_INT("INPUT_TYPE", int32(EMegaLightsInput::Count));
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FTileType, FNumSamplesPerPixel1d, FGuideByHistory, FInputType, FDebugMode>;
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
EMegaLightsInput InputType = EMegaLightsInput(PermutationVector.Get<FInputType>());
if (MegaLights::GetShadingTileTypes(InputType).Find(PermutationVector.Get<FTileType>()) == INDEX_NONE)
{
return false;
}
if (PermutationVector.Get<FGuideByHistory>() && !MegaLights::SupportsGuideByHistory(InputType))
{
return false;
}
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
// precache all tile types
EMegaLightsInput InputType = EMegaLightsInput(PermutationVector.Get<FInputType>());
int NumSamplesPerPixel1d = PermutationVector.Get<FNumSamplesPerPixel1d>();
const FIntPoint NumSamplesPerPixel2d = MegaLights::GetNumSamplesPerPixel2d(InputType);
if (NumSamplesPerPixel1d != (NumSamplesPerPixel2d.X * NumSamplesPerPixel2d.Y))
{
return EShaderPermutationPrecacheRequest::NotUsed;
}
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return EShaderPermutationPrecacheRequest::Precached;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerPixel1d = PermutationVector.Get<FNumSamplesPerPixel1d>();
const FIntPoint NumSamplesPerPixel2d = MegaLights::GetNumSamplesPerPixel2d(NumSamplesPerPixel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_X"), NumSamplesPerPixel2d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_Y"), NumSamplesPerPixel2d.Y);
if (IsMetalPlatform(Parameters.Platform))
{
OutEnvironment.SetDefine(TEXT("FORCE_DISABLE_GLINTS_AA"), 1); // SUBSTRATE_TODO Temporary, while Metal compute does not have derivatives.
}
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
}
};
IMPLEMENT_GLOBAL_SHADER(FGenerateLightSamplesCS, "/Engine/Private/MegaLights/MegaLightsSampling.usf", "GenerateLightSamplesCS", SF_Compute);
class FVolumeGenerateLightSamplesCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FVolumeGenerateLightSamplesCS)
SHADER_USE_PARAMETER_STRUCT(FVolumeGenerateLightSamplesCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsVolumeParameters, MegaLightsVolumeParameters)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, VolumeVisibleLightHashHistory)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture3D<float>, RWVolumeLightSamples)
SHADER_PARAMETER(FIntVector, HistoryVolumeVisibleLightHashViewSizeInTiles)
SHADER_PARAMETER(FIntVector, VolumeVisibleLightHashTileSize)
SHADER_PARAMETER(float, VolumeGuideByHistoryHiddenRatio)
END_SHADER_PARAMETER_STRUCT()
class FTranslucencyLightingVolume : SHADER_PERMUTATION_BOOL("TRANSLUCENCY_LIGHTING_VOLUME");
class FNumSamplesPerVoxel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_VOXEL_1D", 2, 4);
class FLightSoftFading : SHADER_PERMUTATION_BOOL("USE_LIGHT_SOFT_FADING");
class FUseLightFunctionAtlas : SHADER_PERMUTATION_BOOL("USE_LIGHT_FUNCTION_ATLAS");
class FGuideByHistory : SHADER_PERMUTATION_BOOL("GUIDE_BY_HISTORY");
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FTranslucencyLightingVolume, FNumSamplesPerVoxel1d, FLightSoftFading, FUseLightFunctionAtlas, FGuideByHistory, FDebugMode>;
static int32 GetGroupSize()
{
return 4;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerVoxel1d = PermutationVector.Get<FNumSamplesPerVoxel1d>();
const FIntVector NumSamplesPerVoxel3d = MegaLights::GetNumSamplesPerVoxel3d(NumSamplesPerVoxel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_X"), NumSamplesPerVoxel3d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_Y"), NumSamplesPerVoxel3d.Y);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_Z"), NumSamplesPerVoxel3d.Z);
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
OutEnvironment.CompilerFlags.Add(CFLAG_HLSL2021);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return FGlobalShader::ShouldPrecachePermutation(Parameters);
}
};
IMPLEMENT_GLOBAL_SHADER(FVolumeGenerateLightSamplesCS, "/Engine/Private/MegaLights/MegaLightsVolumeSampling.usf", "VolumeGenerateLightSamplesCS", SF_Compute);
class FClearLightSamplesCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FClearLightSamplesCS)
SHADER_USE_PARAMETER_STRUCT(FClearLightSamplesCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RDG_BUFFER_ACCESS(IndirectArgs, ERHIAccess::IndirectArgs)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float>, RWDownsampledSceneDepth)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<UNORM float3>, RWDownsampledSceneWorldNormal)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, RWLightSamples)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, RWLightSampleRays)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DownsampledTileAllocator)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DownsampledTileData)
END_SHADER_PARAMETER_STRUCT()
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FDebugMode>;
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return FGlobalShader::ShouldPrecachePermutation(Parameters);
}
};
IMPLEMENT_GLOBAL_SHADER(FClearLightSamplesCS, "/Engine/Private/MegaLights/MegaLightsSampling.usf", "ClearLightSamplesCS", SF_Compute);
class FShadeLightSamplesCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FShadeLightSamplesCS)
SHADER_USE_PARAMETER_STRUCT(FShadeLightSamplesCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RDG_BUFFER_ACCESS(IndirectArgs, ERHIAccess::IndirectArgs)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float3>, RWResolvedDiffuseLighting)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float3>, RWResolvedSpecularLighting)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float>, RWShadingConfidence)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, TileAllocator)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, TileData)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, LightSamples)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, HairTransmittanceMaskTexture)
SHADER_PARAMETER(uint32, UseShadingConfidence)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 8;
}
class FTileType : SHADER_PERMUTATION_INT("TILE_TYPE", (int32)MegaLights::ETileType::SHADING_MAX_SUBSTRATE);
class FDownsampleFactor : SHADER_PERMUTATION_RANGE_INT("DOWNSAMPLE_FACTOR", 1, 2);
class FNumSamplesPerPixel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_PIXEL_1D", 2, 4, 16);
class FInputType : SHADER_PERMUTATION_INT("INPUT_TYPE", int32(EMegaLightsInput::Count));
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FTileType, FDownsampleFactor, FNumSamplesPerPixel1d, FInputType, FDebugMode>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
EMegaLightsInput InputType = EMegaLightsInput(PermutationVector.Get<FInputType>());
if (MegaLights::GetShadingTileTypes(InputType).Find(PermutationVector.Get<FTileType>()) == INDEX_NONE)
{
return false;
}
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return EShaderPermutationPrecacheRequest::Precached;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerPixel1d = PermutationVector.Get<FNumSamplesPerPixel1d>();
const FIntPoint NumSamplesPerPixel2d = MegaLights::GetNumSamplesPerPixel2d(NumSamplesPerPixel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_X"), NumSamplesPerPixel2d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_Y"), NumSamplesPerPixel2d.Y);
if (IsMetalPlatform(Parameters.Platform))
{
OutEnvironment.SetDefine(TEXT("FORCE_DISABLE_GLINTS_AA"), 1); // SUBSTRATE_TODO Temporary, while Metal compute does not have derivatives.
}
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
}
};
IMPLEMENT_GLOBAL_SHADER(FShadeLightSamplesCS, "/Engine/Private/MegaLights/MegaLightsShading.usf", "ShadeLightSamplesCS", SF_Compute);
class FVisibleLightHashCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FVisibleLightHashCS)
SHADER_USE_PARAMETER_STRUCT(FVisibleLightHashCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWVisibleLightHash)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWVisibleLightMaskHash)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, LightSamples)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, LightSampleRays)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 8;
}
class FNumSamplesPerPixel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_PIXEL_1D", 2, 4, 16);
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FNumSamplesPerPixel1d, FDebugMode>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return EShaderPermutationPrecacheRequest::Precached;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerPixel1d = PermutationVector.Get<FNumSamplesPerPixel1d>();
const FIntPoint NumSamplesPerPixel2d = MegaLights::GetNumSamplesPerPixel2d(NumSamplesPerPixel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_X"), NumSamplesPerPixel2d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_Y"), NumSamplesPerPixel2d.Y);
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
OutEnvironment.CompilerFlags.Add(CFLAG_HLSL2021);
}
};
IMPLEMENT_GLOBAL_SHADER(FVisibleLightHashCS, "/Engine/Private/MegaLights/MegaLightsVisibleLightHash.usf", "VisibleLightHashCS", SF_Compute);
class FVolumeShadeLightSamplesCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FVolumeShadeLightSamplesCS)
SHADER_USE_PARAMETER_STRUCT(FVolumeShadeLightSamplesCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture3D<float3>, RWVolumeResolvedLighting)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture3D<float3>, RWTranslucencyVolumeResolvedLightingAmbient)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture3D<float3>, RWTranslucencyVolumeResolvedLightingDirectional)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsVolumeParameters, MegaLightsVolumeParameters)
SHADER_PARAMETER_RDG_TEXTURE(Texture3D<uint>, VolumeLightSamples)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 4;
}
class FTranslucencyLightingVolume : SHADER_PERMUTATION_BOOL("TRANSLUCENCY_LIGHTING_VOLUME");
class FDownsampleFactor : SHADER_PERMUTATION_RANGE_INT("VOLUME_DOWNSAMPLE_FACTOR", 1, 2);
class FNumSamplesPerVoxel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_VOXEL_1D", 2, 4);
class FLightSoftFading : SHADER_PERMUTATION_BOOL("USE_LIGHT_SOFT_FADING");
class FUseLightFunctionAtlas : SHADER_PERMUTATION_BOOL("USE_LIGHT_FUNCTION_ATLAS");
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FTranslucencyLightingVolume, FDownsampleFactor, FNumSamplesPerVoxel1d, FLightSoftFading, FUseLightFunctionAtlas, FDebugMode>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerVoxel1d = PermutationVector.Get<FNumSamplesPerVoxel1d>();
const FIntVector NumSamplesPerVoxel3d = MegaLights::GetNumSamplesPerVoxel3d(NumSamplesPerVoxel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_X"), NumSamplesPerVoxel3d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_Y"), NumSamplesPerVoxel3d.Y);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_Z"), NumSamplesPerVoxel3d.Z);
OutEnvironment.CompilerFlags.Add(CFLAG_Wave32);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return FGlobalShader::ShouldPrecachePermutation(Parameters);
}
};
IMPLEMENT_GLOBAL_SHADER(FVolumeShadeLightSamplesCS, "/Engine/Private/MegaLights/MegaLightsVolumeShading.usf", "VolumeShadeLightSamplesCS", SF_Compute);
class FVolumeVisibleLightHashCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FVolumeVisibleLightHashCS)
SHADER_USE_PARAMETER_STRUCT(FVolumeVisibleLightHashCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWVisibleLightHash)
SHADER_PARAMETER_RDG_TEXTURE(Texture3D<uint>, LightSamples)
SHADER_PARAMETER(FIntVector, VolumeVisibleLightHashTileSize)
SHADER_PARAMETER(FIntVector, VolumeVisibleLightHashViewSizeInTiles)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 4;
}
class FNumSamplesPerVoxel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_VOXEL_1D", 2, 4);
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FNumSamplesPerVoxel1d, FDebugMode>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return EShaderPermutationPrecacheRequest::Precached;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerPixel1d = PermutationVector.Get<FNumSamplesPerVoxel1d>();
const int32 NumSamplesPerVoxel1d = PermutationVector.Get<FNumSamplesPerVoxel1d>();
const FIntVector NumSamplesPerVoxel3d = MegaLights::GetNumSamplesPerVoxel3d(NumSamplesPerVoxel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_X"), NumSamplesPerVoxel3d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_Y"), NumSamplesPerVoxel3d.Y);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_VOXEL_3D_Z"), NumSamplesPerVoxel3d.Z);
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
OutEnvironment.CompilerFlags.Add(CFLAG_HLSL2021);
}
};
IMPLEMENT_GLOBAL_SHADER(FVolumeVisibleLightHashCS, "/Engine/Private/MegaLights/MegaLightsVisibleLightHash.usf", "VolumeVisibleLightHashCS", SF_Compute);
class FVolumeFilterVisibleLightHashCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FVolumeFilterVisibleLightHashCS)
SHADER_USE_PARAMETER_STRUCT(FVolumeFilterVisibleLightHashCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER(FIntVector, VolumeVisibleLightHashViewSizeInTiles)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWVisibleLightHash)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, VisibleLightHashBuffer)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 4;
}
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FDebugMode>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return EShaderPermutationPrecacheRequest::Precached;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
OutEnvironment.CompilerFlags.Add(CFLAG_HLSL2021);
}
};
IMPLEMENT_GLOBAL_SHADER(FVolumeFilterVisibleLightHashCS, "/Engine/Private/MegaLights/MegaLightsFilterVisibleLightHash.usf", "VolumeFilterVisibleLightHashCS", SF_Compute);
class FClearResolvedLightingCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FClearResolvedLightingCS)
SHADER_USE_PARAMETER_STRUCT(FClearResolvedLightingCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RDG_BUFFER_ACCESS(IndirectArgs, ERHIAccess::IndirectArgs)
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float3>, RWResolvedDiffuseLighting)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float3>, RWResolvedSpecularLighting)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, TileAllocator)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, TileData)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
}
};
IMPLEMENT_GLOBAL_SHADER(FClearResolvedLightingCS, "/Engine/Private/MegaLights/MegaLightsShading.usf", "ClearResolvedLightingCS", SF_Compute);
class FDenoiserTemporalCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FDenoiserTemporalCS)
SHADER_USE_PARAMETER_STRUCT(FDenoiserTemporalCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float4>, ResolvedDiffuseLighting)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float4>, ResolvedSpecularLighting)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, ShadingConfidenceTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float4>, DiffuseLightingAndSecondMomentHistoryTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float4>, SpecularLightingAndSecondMomentHistoryTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UNORM float>, NumFramesAccumulatedHistoryTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, MegaLightsDepthHistory)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float4>, MegaLightsNormalAndShading)
SHADER_PARAMETER(FVector4f, HistoryScreenPositionScaleBias)
SHADER_PARAMETER(FVector4f, HistoryUVMinMax)
SHADER_PARAMETER(FVector4f, HistoryGatherUVMinMax)
SHADER_PARAMETER(FVector4f, HistoryBufferSizeAndInvSize)
SHADER_PARAMETER(float, PrevSceneColorPreExposureCorrection)
SHADER_PARAMETER(float, MinFramesAccumulatedForHistoryMiss)
SHADER_PARAMETER(float, MinFramesAccumulatedForHighConfidence)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWDiffuseLightingAndSecondMoment)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWSpecularLightingAndSecondMoment)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<UNORM float>, RWNumFramesAccumulated)
END_SHADER_PARAMETER_STRUCT()
class FValidHistory : SHADER_PERMUTATION_BOOL("VALID_HISTORY");
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
class FInputType : SHADER_PERMUTATION_INT("INPUT_TYPE", int32(EMegaLightsInput::Count));
using FPermutationDomain = TShaderPermutationDomain<FValidHistory, FDebugMode, FInputType>;
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
EMegaLightsInput InputType = EMegaLightsInput(PermutationVector.Get<FInputType>());
if (PermutationVector.Get<FValidHistory>() && !MegaLights::SupportsTemporalFilter(InputType))
{
return false;
}
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return FGlobalShader::ShouldPrecachePermutation(Parameters);
}
};
IMPLEMENT_GLOBAL_SHADER(FDenoiserTemporalCS, "/Engine/Private/MegaLights/MegaLightsDenoiserTemporal.usf", "DenoiserTemporalCS", SF_Compute);
class FDenoiserSpatialCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FDenoiserSpatialCS)
SHADER_USE_PARAMETER_STRUCT(FDenoiserSpatialCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWSceneColor)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float3>, DiffuseLightingAndSecondMomentTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float3>, SpecularLightingAndSecondMomentTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, ShadingConfidenceTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UNORM float>, NumFramesAccumulatedTexture)
SHADER_PARAMETER(float, SpatialFilterDepthWeightScale)
SHADER_PARAMETER(float, SpatialFilterKernelRadius)
SHADER_PARAMETER(uint32, SpatialFilterNumSamples)
SHADER_PARAMETER(float, SpatialFilterMaxDisocclusionFrames)
END_SHADER_PARAMETER_STRUCT()
class FSpatialFilter : SHADER_PERMUTATION_BOOL("SPATIAL_FILTER");
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
class FInputType : SHADER_PERMUTATION_INT("INPUT_TYPE", int32(EMegaLightsInput::Count));
using FPermutationDomain = TShaderPermutationDomain<FSpatialFilter, FDebugMode, FInputType>;
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
EMegaLightsInput InputType = EMegaLightsInput(PermutationVector.Get<FInputType>());
if (PermutationVector.Get<FSpatialFilter>() && !MegaLights::SupportsSpatialFilter(InputType))
{
return false;
}
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return FGlobalShader::ShouldPrecachePermutation(Parameters);
}
};
IMPLEMENT_GLOBAL_SHADER(FDenoiserSpatialCS, "/Engine/Private/MegaLights/MegaLightsDenoiserSpatial.usf", "DenoiserSpatialCS", SF_Compute);
class FFilterVisibleLightHashCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FFilterVisibleLightHashCS)
SHADER_USE_PARAMETER_STRUCT(FFilterVisibleLightHashCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWVisibleLightHash)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWVisibleLightMaskHash)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, VisibleLightHashBuffer)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, VisibleLightMaskHashBuffer)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 8;
}
class FDebugMode : SHADER_PERMUTATION_BOOL("DEBUG_MODE");
using FPermutationDomain = TShaderPermutationDomain<FDebugMode>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FDebugMode>())
{
return EShaderPermutationPrecacheRequest::NotPrecached;
}
return EShaderPermutationPrecacheRequest::Precached;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
MegaLights::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
OutEnvironment.CompilerFlags.Add(CFLAG_HLSL2021);
}
};
IMPLEMENT_GLOBAL_SHADER(FFilterVisibleLightHashCS, "/Engine/Private/MegaLights/MegaLightsFilterVisibleLightHash.usf", "FilterVisibleLightHashCS", SF_Compute);
class FMegaLightHairTransmittanceCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FMegaLightHairTransmittanceCS)
SHADER_USE_PARAMETER_STRUCT(FMegaLightHairTransmittanceCS, FGlobalShader)
class FNumSamplesPerPixel1d : SHADER_PERMUTATION_SPARSE_INT("NUM_SAMPLES_PER_PIXEL_1D", 2, 4, 16);
using FPermutationDomain = TShaderPermutationDomain<FNumSamplesPerPixel1d>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FMegaLightsParameters, MegaLightsParameters)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualVoxelParameters, VirtualVoxel)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, LightSamples)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, LightSampleRays)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, RWTransmittanceMaskTexture)
END_SHADER_PARAMETER_STRUCT()
static int32 GetGroupSize()
{
return 8;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return MegaLights::ShouldCompileShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
FForwardLightingParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE"), GetGroupSize());
OutEnvironment.SetDefine(TEXT("INPUT_TYPE"), TEXT("INPUT_TYPE_HAIRSTRANDS"));
FPermutationDomain PermutationVector(Parameters.PermutationId);
const int32 NumSamplesPerPixel1d = PermutationVector.Get<FNumSamplesPerPixel1d>();
const FIntPoint NumSamplesPerPixel2d = MegaLights::GetNumSamplesPerPixel2d(NumSamplesPerPixel1d);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_X"), NumSamplesPerPixel2d.X);
OutEnvironment.SetDefine(TEXT("NUM_SAMPLES_PER_PIXEL_2D_Y"), NumSamplesPerPixel2d.Y);
}
};
IMPLEMENT_GLOBAL_SHADER(FMegaLightHairTransmittanceCS, "/Engine/Private/MegaLights/MegaLights.usf", "HairTransmittanceCS", SF_Compute);
DECLARE_GPU_STAT(MegaLights);
extern int32 GetTranslucencyLightingVolumeDim();
/**
* Single pass batched light rendering using ray tracing (distance field or triangle) for stochastic light (BRDF and visibility) sampling.
*/
static void InternalRenderMegaLights(
FRDGBuilder& GraphBuilder,
const int32 ViewIndex,
const FViewInfo& View,
const FSceneViewFamily& ViewFamily,
const FScene* Scene,
const FSceneTextures& SceneTextures,
FRDGTextureRef LightingChannelsTexture,
const FSortedLightSetSceneInfo& SortedLightSet,
const FVirtualShadowMapArray* VirtualShadowMapArray,
FMegaLightsVolume* MegaLightsVolume,
const bool bShouldRenderVolumetricFog,
const bool bShouldRenderTranslucencyVolume,
TUniformBufferRef<FBlueNoise> BlueNoiseUniformBuffer,
EMegaLightsInput InputType,
FRDGTextureRef OutputColorTarget)
{
{
// History reset for debugging purposes
bool bResetHistory = false;
if (GMegaLightsResetEveryNthFrame > 0 && (ViewFamily.FrameNumber % (uint32)GMegaLightsResetEveryNthFrame) == 0)
{
bResetHistory = true;
}
if (GMegaLightsReset != 0)
{
GMegaLightsReset = 0;
bResetHistory = true;
}
if (MegaLightsVolume)
{
MegaLightsVolume->Texture = nullptr;
}
const bool bDebug = MegaLights::GetDebugMode(InputType) != 0;
const bool bVolumeDebug = MegaLightsVolume::GetDebugMode() != 0;
const bool bTranslucencyVolumeDebug = MegaLightsTranslucencyVolume::GetDebugMode() != 0;
const FIntPoint NumSamplesPerPixel2d = MegaLights::GetNumSamplesPerPixel2d(InputType);
const FIntVector NumSamplesPerVoxel3d = MegaLightsVolume::GetNumSamplesPerVoxel3d();
const FIntVector NumSamplesPerTranslucencyVoxel3d = MegaLightsTranslucencyVolume::GetNumSamplesPerVoxel3d();
const uint32 DownsampleFactor = MegaLights::GetDownsampleFactor(InputType);
const FIntPoint DownsampledViewSize = FIntPoint::DivideAndRoundUp(View.ViewRect.Size(), DownsampleFactor);
const FIntPoint SampleViewSize = DownsampledViewSize * NumSamplesPerPixel2d;
const FIntPoint DownsampledBufferSize = FIntPoint::DivideAndRoundUp(SceneTextures.Config.Extent, DownsampleFactor);
const FIntPoint SampleBufferSize = DownsampledBufferSize * NumSamplesPerPixel2d;
const FIntPoint DonwnsampledSampleBufferSize = DownsampledBufferSize * NumSamplesPerPixel2d;
FRDGTextureRef DownsampledSceneDepth = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(DownsampledBufferSize, PF_R32_FLOAT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.DownsampledSceneDepth"));
FRDGTextureRef DownsampledSceneWorldNormal = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(DownsampledBufferSize, PF_A2B10G10R10, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.DownsampledSceneWorldNormal"));
FRDGTextureRef LightSamples = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(DonwnsampledSampleBufferSize, PF_R32_UINT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.LightSamples"));
FRDGTextureRef LightSampleRays = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(DonwnsampledSampleBufferSize, PF_R32_UINT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.LightSampleRays"));
const bool bSpatial = MegaLights::SupportsSpatialFilter(InputType) && CVarMegaLightsSpatial.GetValueOnRenderThread() != 0;
const bool bTemporal = MegaLights::SupportsTemporalFilter(InputType) && CVarMegaLightsTemporal.GetValueOnRenderThread() != 0;
const FIntPoint VisibleLightHashSizeInTiles = FMath::DivideAndRoundUp<FIntPoint>(SceneTextures.Config.Extent, MegaLights::TileSize);
const FIntPoint VisibleLightHashViewMinInTiles = FMath::DivideAndRoundUp<FIntPoint>(View.ViewRect.Min, MegaLights::TileSize);
const FIntPoint VisibleLightHashViewSizeInTiles = FMath::DivideAndRoundUp<FIntPoint>(View.ViewRect.Size(), MegaLights::TileSize);
const uint32 VisibleLightHashBufferSize = VisibleLightHashSizeInTiles.X * VisibleLightHashSizeInTiles.Y * MegaLights::VisibleLightHashSize;
FVolumetricFogGlobalData VolumetricFogParamaters;
if (bShouldRenderVolumetricFog)
{
SetupVolumetricFogGlobalData(View, VolumetricFogParamaters);
}
const uint32 VolumeDownsampleFactor = MegaLightsVolume::GetDownsampleFactor();
const FIntVector VolumeViewSize = VolumetricFogParamaters.ViewGridSizeInt;
const FIntVector VolumeBufferSize = VolumetricFogParamaters.ResourceGridSizeInt;
const FIntVector VolumeDownsampledBufferSize = FIntVector::DivideAndRoundUp(VolumetricFogParamaters.ResourceGridSizeInt, VolumeDownsampleFactor);
const FIntVector VolumeDownsampledViewSize = FIntVector::DivideAndRoundUp(VolumetricFogParamaters.ViewGridSizeInt, VolumeDownsampleFactor);
const FIntVector VolumeSampleViewSize = VolumeDownsampledViewSize * NumSamplesPerVoxel3d;
const FIntVector VolumeSampleBufferSize = VolumeDownsampledBufferSize * NumSamplesPerVoxel3d;
const FIntVector VolumeVisibleLightHashTileSize = FIntVector(2, 2, 1);
const FIntVector VolumeVisibleLightHashSizeInTiles = FIntVector(
FMath::DivideAndRoundUp(VolumeDownsampledBufferSize.X, VolumeVisibleLightHashTileSize.X),
FMath::DivideAndRoundUp(VolumeDownsampledBufferSize.Y, VolumeVisibleLightHashTileSize.Y),
FMath::DivideAndRoundUp(VolumeDownsampledBufferSize.Z, VolumeVisibleLightHashTileSize.Z));
const FIntVector VolumeVisibleLightHashViewSizeInTiles = FIntVector(
FMath::DivideAndRoundUp(VolumeDownsampledViewSize.X, VolumeVisibleLightHashTileSize.X),
FMath::DivideAndRoundUp(VolumeDownsampledViewSize.Y, VolumeVisibleLightHashTileSize.Y),
FMath::DivideAndRoundUp(VolumeDownsampledViewSize.Z, VolumeVisibleLightHashTileSize.Z));
const uint32 VolumeVisibleLightHashBufferSize = VolumeVisibleLightHashSizeInTiles.X * VolumeVisibleLightHashSizeInTiles.Y * VolumeVisibleLightHashSizeInTiles.Z * MegaLights::VisibleLightHashSize;
const uint32 TranslucencyVolumeDownsampleFactor = MegaLightsTranslucencyVolume::GetDownsampleFactor();
const FIntVector TranslucencyVolumeBufferSize = FIntVector(GetTranslucencyLightingVolumeDim());
const FIntVector TranslucencyVolumeDownsampledBufferSize = FIntVector::DivideAndRoundUp(TranslucencyVolumeBufferSize, TranslucencyVolumeDownsampleFactor);
const FIntVector TranslucencyVolumeSampleBufferSize = TranslucencyVolumeDownsampledBufferSize * NumSamplesPerTranslucencyVoxel3d;
const FIntVector TranslucencyVolumeVisibleLightHashTileSize = FIntVector(1, 1, 1);
const FIntVector TranslucencyVolumeVisibleLightHashSizeInTiles = FIntVector(
FMath::DivideAndRoundUp(TranslucencyVolumeDownsampledBufferSize.X, TranslucencyVolumeVisibleLightHashTileSize.X),
FMath::DivideAndRoundUp(TranslucencyVolumeDownsampledBufferSize.Y, TranslucencyVolumeVisibleLightHashTileSize.Y),
FMath::DivideAndRoundUp(TranslucencyVolumeDownsampledBufferSize.Z, TranslucencyVolumeVisibleLightHashTileSize.Z));
const uint32 TranslucencyVolumeVisibleLightHashBufferSize =
TranslucencyVolumeVisibleLightHashSizeInTiles.X *
TranslucencyVolumeVisibleLightHashSizeInTiles.Y *
TranslucencyVolumeVisibleLightHashSizeInTiles.Z *
MegaLights::VisibleLightHashSize;
const bool bGuideByHistory = MegaLights::SupportsGuideByHistory(InputType) && CVarMegaLightsGuideByHistory.GetValueOnRenderThread() != 0;
const bool bVolumeGuideByHistory = MegaLights::SupportsGuideByHistory(InputType) && CVarMegaLightsVolumeGuideByHistory.GetValueOnRenderThread() != 0;
const bool bTranslucencyVolumeGuideByHistory = MegaLights::SupportsGuideByHistory(InputType) && CVarMegaLightsTranslucencyVolumeGuideByHistory.GetValueOnRenderThread() != 0;
FVector4f HistoryScreenPositionScaleBias = FVector4f(0.0f, 0.0f, 0.0f, 0.0f);
FVector4f HistoryUVMinMax = FVector4f(0.0f, 0.0f, 0.0f, 0.0f);
FVector4f HistoryGatherUVMinMax = FVector4f(0.0f, 0.0f, 0.0f, 0.0f);
FVector4f HistoryBufferSizeAndInvSize = FVector4f(0.0f, 0.0f, 0.0f, 0.0f);
FIntPoint HistoryVisibleLightHashViewMinInTiles = 0;
FIntPoint HistoryVisibleLightHashViewSizeInTiles = 0;
FRDGTextureRef DiffuseLightingAndSecondMomentHistory = nullptr;
FRDGTextureRef SpecularLightingAndSecondMomentHistory = nullptr;
FRDGTextureRef SceneDepthHistory = nullptr;
FRDGTextureRef SceneNormalAndShadingHistory = nullptr;
FRDGTextureRef NumFramesAccumulatedHistory = nullptr;
FRDGBufferRef VisibleLightHashHistory = nullptr;
FRDGBufferRef VisibleLightMaskHashHistory = nullptr;
FIntVector HistoryVolumeVisibleLightHashViewSizeInTiles = FIntVector::ZeroValue;
FRDGBufferRef VolumeVisibleLightHashHistory = nullptr;
FIntVector HistoryTranslucencyVolumeVisibleLightHashSizeInTiles = FIntVector::ZeroValue;
FRDGBufferRef TranslucencyVolumeVisibleLightHashHistory[TVC_MAX] = {};
if (View.ViewState)
{
const FMegaLightsViewState& MegaLightsViewState = View.ViewState->MegaLights;
const FStochasticLightingViewState& StochasticLightingViewState = View.ViewState->StochasticLighting;
if (!View.bCameraCut
&& !View.bPrevTransformsReset
&& !bResetHistory)
{
HistoryScreenPositionScaleBias = MegaLightsViewState.HistoryScreenPositionScaleBias;
HistoryUVMinMax = MegaLightsViewState.HistoryUVMinMax;
HistoryGatherUVMinMax = MegaLightsViewState.HistoryGatherUVMinMax;
HistoryBufferSizeAndInvSize = MegaLightsViewState.HistoryBufferSizeAndInvSize;
HistoryVisibleLightHashViewMinInTiles = MegaLightsViewState.HistoryVisibleLightHashViewMinInTiles;
HistoryVisibleLightHashViewSizeInTiles = MegaLightsViewState.HistoryVisibleLightHashViewSizeInTiles;
HistoryVolumeVisibleLightHashViewSizeInTiles = MegaLightsViewState.HistoryVolumeVisibleLightHashViewSizeInTiles;
HistoryTranslucencyVolumeVisibleLightHashSizeInTiles = MegaLightsViewState.HistoryTranslucencyVolumeVisibleLightHashSizeInTiles;
if (StochasticLightingViewState.SceneDepthHistory)
{
SceneDepthHistory = GraphBuilder.RegisterExternalTexture(StochasticLightingViewState.SceneDepthHistory);
}
if (StochasticLightingViewState.SceneNormalHistory)
{
SceneNormalAndShadingHistory = GraphBuilder.RegisterExternalTexture(StochasticLightingViewState.SceneNormalHistory);
}
if (bTemporal &&
MegaLightsViewState.DiffuseLightingAndSecondMomentHistory
&& MegaLightsViewState.SpecularLightingAndSecondMomentHistory
&& MegaLightsViewState.NumFramesAccumulatedHistory)
{
DiffuseLightingAndSecondMomentHistory = GraphBuilder.RegisterExternalTexture(MegaLightsViewState.DiffuseLightingAndSecondMomentHistory);
SpecularLightingAndSecondMomentHistory = GraphBuilder.RegisterExternalTexture(MegaLightsViewState.SpecularLightingAndSecondMomentHistory);
NumFramesAccumulatedHistory = GraphBuilder.RegisterExternalTexture(MegaLightsViewState.NumFramesAccumulatedHistory);
}
if (bGuideByHistory
&& MegaLightsViewState.VisibleLightHashHistory
&& MegaLightsViewState.VisibleLightMaskHashHistory)
{
VisibleLightHashHistory = GraphBuilder.RegisterExternalBuffer(MegaLightsViewState.VisibleLightHashHistory);
VisibleLightMaskHashHistory = GraphBuilder.RegisterExternalBuffer(MegaLightsViewState.VisibleLightMaskHashHistory);
}
if (bVolumeGuideByHistory
&& MegaLightsViewState.VolumeVisibleLightHashHistory)
{
VolumeVisibleLightHashHistory = GraphBuilder.RegisterExternalBuffer(MegaLightsViewState.VolumeVisibleLightHashHistory);
}
if (bTranslucencyVolumeGuideByHistory
&& MegaLightsViewState.TranslucencyVolume0VisibleLightHashHistory
&& MegaLightsViewState.TranslucencyVolume1VisibleLightHashHistory
&& TranslucencyVolumeVisibleLightHashBufferSize == MegaLightsViewState.TranslucencyVolume0VisibleLightHashHistory->GetSize() / sizeof(uint32)
&& TranslucencyVolumeVisibleLightHashBufferSize == MegaLightsViewState.TranslucencyVolume1VisibleLightHashHistory->GetSize() / sizeof(uint32))
{
TranslucencyVolumeVisibleLightHashHistory[0] = GraphBuilder.RegisterExternalBuffer(MegaLightsViewState.TranslucencyVolume0VisibleLightHashHistory);
TranslucencyVolumeVisibleLightHashHistory[1] = GraphBuilder.RegisterExternalBuffer(MegaLightsViewState.TranslucencyVolume1VisibleLightHashHistory);
}
}
}
// Setup the light function atlas
const bool bUseLightFunctionAtlas = LightFunctionAtlas::IsEnabled(View, LightFunctionAtlas::ELightFunctionAtlasSystem::MegaLights);
const FIntPoint ViewSizeInTiles = FIntPoint::DivideAndRoundUp(View.ViewRect.Size(), MegaLights::TileSize);
const int32 TileDataStride = ViewSizeInTiles.X * ViewSizeInTiles.Y;
const FIntPoint DownsampledViewSizeInTiles = FIntPoint::DivideAndRoundUp(DownsampledViewSize, MegaLights::TileSize);
const int32 DownsampledTileDataStride = DownsampledViewSizeInTiles.X * DownsampledViewSizeInTiles.Y;
FMegaLightsParameters MegaLightsParameters;
{
MegaLightsParameters.ViewUniformBuffer = View.ViewUniformBuffer;
MegaLightsParameters.Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
MegaLightsParameters.SceneTextures = GetSceneTextureParameters(GraphBuilder, SceneTextures.UniformBuffer);
MegaLightsParameters.SceneTexturesStruct = SceneTextures.UniformBuffer;
MegaLightsParameters.Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
MegaLightsParameters.HairStrands = HairStrands::BindHairStrandsViewUniformParameters(View);
MegaLightsParameters.ForwardLightStruct = View.ForwardLightingResources.ForwardLightUniformBuffer;
MegaLightsParameters.LightFunctionAtlas = LightFunctionAtlas::BindGlobalParameters(GraphBuilder, View);
MegaLightsParameters.LightingChannelParameters = GetSceneLightingChannelParameters(GraphBuilder, View, LightingChannelsTexture);
MegaLightsParameters.BlueNoise = BlueNoiseUniformBuffer;
MegaLightsParameters.PreIntegratedGF = GSystemTextures.PreintegratedGF->GetRHI();
MegaLightsParameters.PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
MegaLightsParameters.UnjitteredClipToTranslatedWorld = FMatrix44f(View.ViewMatrices.ComputeInvProjectionNoAAMatrix() * View.ViewMatrices.GetTranslatedViewMatrix().GetTransposed()); // LWC_TODO: Precision loss?
MegaLightsParameters.UnjitteredPrevTranslatedWorldToClip = FMatrix44f(FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation()) * View.PrevViewInfo.ViewMatrices.GetViewMatrix() * View.PrevViewInfo.ViewMatrices.ComputeProjectionNoAAMatrix());
MegaLightsParameters.DownsampledViewMin = FIntPoint::DivideAndRoundUp(View.ViewRect.Min, DownsampleFactor);
MegaLightsParameters.DownsampledViewSize = DownsampledViewSize;
MegaLightsParameters.SampleViewMin = FIntPoint::DivideAndRoundUp(View.ViewRect.Min, DownsampleFactor) * NumSamplesPerPixel2d;
MegaLightsParameters.SampleViewSize = SampleViewSize;
MegaLightsParameters.DownsampleFactorMultShift = FMath::FloorLog2(DownsampleFactor);
MegaLightsParameters.NumSamplesPerPixel = NumSamplesPerPixel2d;
MegaLightsParameters.NumSamplesPerPixelDivideShift.X = FMath::FloorLog2(NumSamplesPerPixel2d.X);
MegaLightsParameters.NumSamplesPerPixelDivideShift.Y = FMath::FloorLog2(NumSamplesPerPixel2d.Y);
MegaLightsParameters.MegaLightsStateFrameIndex = MegaLights::GetStateFrameIndex(View.ViewState);
MegaLightsParameters.DownsampledSceneDepth = DownsampledSceneDepth;
MegaLightsParameters.DownsampledSceneWorldNormal = DownsampledSceneWorldNormal;
MegaLightsParameters.DownsampledBufferInvSize = FVector2f(1.0f) / DownsampledBufferSize;
MegaLightsParameters.MinSampleWeight = FMath::Max(CVarMegaLightsMinSampleWeight.GetValueOnRenderThread(), 0.0f);
MegaLightsParameters.MaxShadingWeight = FMath::Max(CVarMegaLightsMaxShadingWeight.GetValueOnRenderThread(), 0.0f);
MegaLightsParameters.TileDataStride = TileDataStride;
MegaLightsParameters.DownsampledTileDataStride = DownsampledTileDataStride;
MegaLightsParameters.TemporalMaxFramesAccumulated = MegaLights::GetTemporalMaxFramesAccumulated();
MegaLightsParameters.TemporalNeighborhoodClampScale = CVarMegaLightsTemporalNeighborhoodClampScale.GetValueOnRenderThread();
MegaLightsParameters.DebugCursorPosition.X = CVarMegaLightsDebugCursorX.GetValueOnRenderThread();
MegaLightsParameters.DebugCursorPosition.Y = CVarMegaLightsDebugCursorY.GetValueOnRenderThread();
MegaLightsParameters.DebugMode = MegaLights::GetDebugMode(InputType);
MegaLightsParameters.DebugLightId = INDEX_NONE;
MegaLightsParameters.DebugVisualizeLight = CVarMegaLightsDebugVisualizeLight.GetValueOnRenderThread();
MegaLightsParameters.UseIESProfiles = CVarMegaLightsIESProfiles.GetValueOnRenderThread() != 0;
MegaLightsParameters.UseLightFunctionAtlas = bUseLightFunctionAtlas;
// If editor is disabled then we don't have a valid cursor position and have to force it to the center of the screen
if (!GIsEditor && (MegaLightsParameters.DebugCursorPosition.X < 0 || MegaLightsParameters.DebugCursorPosition.Y < 0))
{
MegaLightsParameters.DebugCursorPosition.X = View.ViewRect.Min.X + View.ViewRect.Width() / 2;
MegaLightsParameters.DebugCursorPosition.Y = View.ViewRect.Min.Y + View.ViewRect.Height() / 2;
}
// screen traces use ClosestHZB, volume sampling/shading uses FurthestHZB
MegaLightsParameters.HZBParameters = GetHZBParameters(GraphBuilder, View, EHZBType::All);
MegaLightsParameters.VisibleLightHashViewMinInTiles = VisibleLightHashViewMinInTiles;
MegaLightsParameters.VisibleLightHashViewSizeInTiles = VisibleLightHashViewSizeInTiles;
if (bDebug || bVolumeDebug || bTranslucencyVolumeDebug)
{
const FIntPoint TileCountXY = FIntPoint::DivideAndRoundUp(View.ViewRect.Size(), MegaLights::TileSize);
const uint32 TileCount = TileCountXY.X * TileCountXY.Y;
ShaderPrint::SetEnabled(true);
ShaderPrint::RequestSpaceForLines(4096u + TileCount * 4u);
ShaderPrint::RequestSpaceForTriangles(TileCount * 2u);
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, MegaLightsParameters.ShaderPrintUniformBuffer);
MegaLightsParameters.DebugLightId = CVarMegaLightsDebugLightId.GetValueOnRenderThread();
if (MegaLightsParameters.DebugLightId < 0)
{
for (auto LightIt = Scene->Lights.CreateConstIterator(); LightIt; ++LightIt)
{
const FLightSceneInfoCompact& LightSceneInfoCompact = *LightIt;
const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo;
if (LightSceneInfo->Proxy->IsSelected())
{
MegaLightsParameters.DebugLightId = LightSceneInfo->Id;
break;
}
}
}
}
}
FMegaLightsVolumeParameters MegaLightsVolumeParameters;
{
extern float GInverseSquaredLightDistanceBiasScale;
MegaLightsVolumeParameters.VolumeMinSampleWeight = FMath::Max(CVarMegaLightsVolumeMinSampleWeight.GetValueOnRenderThread(), 0.0f);
MegaLightsVolumeParameters.VolumeMaxShadingWeight = FMath::Max(CVarMegaLightsVolumeMaxShadingWeight.GetValueOnRenderThread(), 0.0f);
MegaLightsVolumeParameters.VolumeDownsampleFactorMultShift = FMath::FloorLog2(VolumeDownsampleFactor);
MegaLightsVolumeParameters.NumSamplesPerVoxel = NumSamplesPerVoxel3d;
MegaLightsVolumeParameters.NumSamplesPerVoxelDivideShift.X = FMath::FloorLog2(NumSamplesPerVoxel3d.X);
MegaLightsVolumeParameters.NumSamplesPerVoxelDivideShift.Y = FMath::FloorLog2(NumSamplesPerVoxel3d.Y);
MegaLightsVolumeParameters.NumSamplesPerVoxelDivideShift.Z = FMath::FloorLog2(NumSamplesPerVoxel3d.Z);
MegaLightsVolumeParameters.DownsampledVolumeViewSize = VolumeDownsampledViewSize;
MegaLightsVolumeParameters.VolumeViewSize = VolumeViewSize;
MegaLightsVolumeParameters.VolumeSampleViewSize = VolumeSampleViewSize;
MegaLightsVolumeParameters.MegaLightsVolumeZParams = VolumetricFogParamaters.GridZParams;
MegaLightsVolumeParameters.MegaLightsVolumePixelSize = VolumetricFogParamaters.FogGridToPixelXY.X;
MegaLightsVolumeParameters.VolumePhaseG = Scene->ExponentialFogs.Num() > 0 ? Scene->ExponentialFogs[0].VolumetricFogScatteringDistribution : 0.0f;
MegaLightsVolumeParameters.VolumeInverseSquaredLightDistanceBiasScale = GInverseSquaredLightDistanceBiasScale;
MegaLightsVolumeParameters.VolumeFrameJitterOffset = VolumetricFogTemporalRandom(View.Family->FrameNumber);
MegaLightsVolumeParameters.UseHZBOcclusionTest = CVarMegaLightsVolumeHZBOcclusionTest.GetValueOnRenderThread();
MegaLightsVolumeParameters.VolumeDebugMode = MegaLightsVolume::GetDebugMode();
MegaLightsVolumeParameters.VolumeDebugSliceIndex = CVarMegaLightsVolumeDebugSliceIndex.GetValueOnRenderThread();
MegaLightsVolumeParameters.LightSoftFading = GetVolumetricFogLightSoftFading();
MegaLightsVolumeParameters.TranslucencyVolumeCascadeIndex = 0;
MegaLightsVolumeParameters.TranslucencyVolumeInvResolution = 0.0f;
}
FMegaLightsVolumeParameters MegaLightsTranslucencyVolumeParameters;
{
extern float GInverseSquaredLightDistanceBiasScale;
MegaLightsTranslucencyVolumeParameters.VolumeMinSampleWeight = FMath::Max(CVarMegaLightsTranslucencyVolumeMinSampleWeight.GetValueOnRenderThread(), 0.0f);
MegaLightsTranslucencyVolumeParameters.VolumeMaxShadingWeight = FMath::Max(CVarMegaLightsTranslucencyVolumeMaxShadingWeight.GetValueOnRenderThread(), 0.0f);
MegaLightsTranslucencyVolumeParameters.VolumeDownsampleFactorMultShift = FMath::FloorLog2(TranslucencyVolumeDownsampleFactor);
MegaLightsTranslucencyVolumeParameters.NumSamplesPerVoxel = NumSamplesPerTranslucencyVoxel3d;
MegaLightsTranslucencyVolumeParameters.NumSamplesPerVoxelDivideShift.X = FMath::FloorLog2(NumSamplesPerTranslucencyVoxel3d.X);
MegaLightsTranslucencyVolumeParameters.NumSamplesPerVoxelDivideShift.Y = FMath::FloorLog2(NumSamplesPerTranslucencyVoxel3d.Y);
MegaLightsTranslucencyVolumeParameters.NumSamplesPerVoxelDivideShift.Z = FMath::FloorLog2(NumSamplesPerTranslucencyVoxel3d.Z);
MegaLightsTranslucencyVolumeParameters.DownsampledVolumeViewSize = TranslucencyVolumeDownsampledBufferSize;
MegaLightsTranslucencyVolumeParameters.VolumeViewSize = TranslucencyVolumeBufferSize;
MegaLightsTranslucencyVolumeParameters.VolumeSampleViewSize = TranslucencyVolumeSampleBufferSize;
MegaLightsTranslucencyVolumeParameters.MegaLightsVolumeZParams = VolumetricFogParamaters.GridZParams;
MegaLightsTranslucencyVolumeParameters.MegaLightsVolumePixelSize = VolumetricFogParamaters.FogGridToPixelXY.X;
MegaLightsTranslucencyVolumeParameters.VolumePhaseG = 0.0f;
MegaLightsTranslucencyVolumeParameters.VolumeInverseSquaredLightDistanceBiasScale = 1.0f;
MegaLightsTranslucencyVolumeParameters.VolumeFrameJitterOffset = FVector3f::ZeroVector;
MegaLightsTranslucencyVolumeParameters.UseHZBOcclusionTest = false;
MegaLightsTranslucencyVolumeParameters.VolumeDebugMode = MegaLightsTranslucencyVolume::GetDebugMode();
MegaLightsTranslucencyVolumeParameters.VolumeDebugSliceIndex = 0;
MegaLightsTranslucencyVolumeParameters.LightSoftFading = GetVolumetricFogLightSoftFading();
MegaLightsTranslucencyVolumeParameters.TranslucencyVolumeCascadeIndex = 0;
MegaLightsTranslucencyVolumeParameters.TranslucencyVolumeInvResolution = 1.0f / GetTranslucencyLightingVolumeDim();
}
const int32 TileTypeCount = Substrate::IsSubstrateEnabled() ? (int32)MegaLights::ETileType::MAX_SUBSTRATE : (int32)MegaLights::ETileType::MAX_LEGACY;
FRDGBufferRef TileAllocator = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), TileTypeCount), TEXT("MegaLights.TileAllocator"));
FRDGBufferRef TileData = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), TileDataStride * TileTypeCount), TEXT("MegaLights.TileData"));
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(TileAllocator), 0);
FRDGBufferRef DownsampledTileAllocator = TileAllocator;
FRDGBufferRef DownsampledTileData = TileData;
// #ml_todo: merge classification passes or reuse downsampled one to create full res tiles
// Run tile classification to generate tiles for the subsequent passes
{
{
FTileClassificationCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FTileClassificationCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->RWTileAllocator = GraphBuilder.CreateUAV(TileAllocator);
PassParameters->RWTileData = GraphBuilder.CreateUAV(TileData);
PassParameters->EnableTexturedRectLights = CVarMegaLightsTexturedRectLights.GetValueOnRenderThread();
FTileClassificationCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FTileClassificationCS::FDownsampledClassification>(false);
PermutationVector.Set<FTileClassificationCS::FDebugMode>(bDebug);
PermutationVector.Set<FTileClassificationCS::FInputType>(uint32(InputType));
auto ComputeShader = View.ShaderMap->GetShader<FTileClassificationCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(View.ViewRect.Size(), FTileClassificationCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("TileClassification %dx%d", View.ViewRect.Size().X, View.ViewRect.Size().Y),
ComputeShader,
PassParameters,
GroupCount);
}
if (DownsampleFactor != 1)
{
DownsampledTileAllocator = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), TileTypeCount), TEXT("MegaLights.DownsampledTileAllocator"));
DownsampledTileData = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), DownsampledTileDataStride * TileTypeCount), TEXT("MegaLights.DownsampledTileData"));
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(DownsampledTileAllocator), 0);
FTileClassificationCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FTileClassificationCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->RWTileAllocator = GraphBuilder.CreateUAV(DownsampledTileAllocator);
PassParameters->RWTileData = GraphBuilder.CreateUAV(DownsampledTileData);
PassParameters->EnableTexturedRectLights = CVarMegaLightsTexturedRectLights.GetValueOnRenderThread();
FTileClassificationCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FTileClassificationCS::FDownsampledClassification>(true);
PermutationVector.Set<FTileClassificationCS::FDebugMode>(bDebug);
PermutationVector.Set<FTileClassificationCS::FInputType>(uint32(InputType));
auto ComputeShader = View.ShaderMap->GetShader<FTileClassificationCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(DownsampledViewSize, FTileClassificationCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("DownsampledTileClassification %dx%d", DownsampledViewSize.X, DownsampledViewSize.Y),
ComputeShader,
PassParameters,
GroupCount);
}
}
FRDGBufferRef TileIndirectArgs = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(TileTypeCount), TEXT("MegaLights.TileIndirectArgs"));
FRDGBufferRef DownsampledTileIndirectArgs = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(TileTypeCount), TEXT("MegaLights.DownsampledTileIndirectArgs"));
// Setup indirect args for classified tiles
{
FInitTileIndirectArgsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FInitTileIndirectArgsCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->RWTileIndirectArgs = GraphBuilder.CreateUAV(TileIndirectArgs);
PassParameters->RWDownsampledTileIndirectArgs = GraphBuilder.CreateUAV(DownsampledTileIndirectArgs);
PassParameters->TileAllocator = GraphBuilder.CreateSRV(TileAllocator);
PassParameters->DownsampledTileAllocator = GraphBuilder.CreateSRV(DownsampledTileAllocator);
auto ComputeShader = View.ShaderMap->GetShader<FInitTileIndirectArgsCS>();
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("InitTileIndirectArgs"),
ComputeShader,
PassParameters,
FIntVector(1, 1, 1));
}
// Build available tile types
const TArray<int32> ShadingTileTypes = MegaLights::GetShadingTileTypes(InputType);
// Generate new candidate light samples
{
FRDGTextureUAVRef DownsampledSceneDepthUAV = GraphBuilder.CreateUAV(DownsampledSceneDepth, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGTextureUAVRef DownsampledSceneWorldNormalUAV = GraphBuilder.CreateUAV(DownsampledSceneWorldNormal, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGTextureUAVRef LightSamplesUAV = GraphBuilder.CreateUAV(LightSamples, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGTextureUAVRef LightSampleRaysUAV = GraphBuilder.CreateUAV(LightSampleRays, ERDGUnorderedAccessViewFlags::SkipBarrier);
// Clear tiles which don't contain any lights or geometry
{
FClearLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FClearLightSamplesCS::FParameters>();
PassParameters->IndirectArgs = DownsampledTileIndirectArgs;
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->RWDownsampledSceneDepth = DownsampledSceneDepthUAV;
PassParameters->RWDownsampledSceneWorldNormal = DownsampledSceneWorldNormalUAV;
PassParameters->RWLightSamples = LightSamplesUAV;
PassParameters->RWLightSampleRays = LightSampleRaysUAV;
PassParameters->DownsampledTileAllocator = GraphBuilder.CreateSRV(DownsampledTileAllocator);
PassParameters->DownsampledTileData = GraphBuilder.CreateSRV(DownsampledTileData);
FClearLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FClearLightSamplesCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FClearLightSamplesCS>(PermutationVector);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("ClearLightSamples"),
ComputeShader,
PassParameters,
DownsampledTileIndirectArgs,
(int32)MegaLights::ETileType::Empty * sizeof(FRHIDispatchIndirectParameters));
}
for (const int32 TileType : ShadingTileTypes)
{
if (!View.bLightGridHasRectLights && IsRectLightTileType((MegaLights::ETileType)TileType))
{
continue;
}
if (!View.bLightGridHasTexturedLights && IsTexturedLightTileType((MegaLights::ETileType)TileType))
{
continue;
}
FGenerateLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FGenerateLightSamplesCS::FParameters>();
PassParameters->IndirectArgs = DownsampledTileIndirectArgs;
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->RWDownsampledSceneDepth = DownsampledSceneDepthUAV;
PassParameters->RWDownsampledSceneWorldNormal = DownsampledSceneWorldNormalUAV;
PassParameters->RWLightSamples = LightSamplesUAV;
PassParameters->RWLightSampleRays = LightSampleRaysUAV;
PassParameters->DownsampledTileAllocator = GraphBuilder.CreateSRV(DownsampledTileAllocator);
PassParameters->DownsampledTileData = GraphBuilder.CreateSRV(DownsampledTileData);
PassParameters->VisibleLightHashHistory = VisibleLightHashHistory != nullptr ? GraphBuilder.CreateSRV(VisibleLightHashHistory) : nullptr;
PassParameters->VisibleLightMaskHashHistory = VisibleLightMaskHashHistory != nullptr ? GraphBuilder.CreateSRV(VisibleLightMaskHashHistory) : nullptr;
PassParameters->GuideByHistoryMode = CVarMegaLightsGuideByHistory.GetValueOnRenderThread();
PassParameters->AreaLightHiddenPDFWeight = CVarMegaLightsGuideByHistoryAreaLightHiddenWeight.GetValueOnRenderThread();
PassParameters->GuideByHistoryHiddenRatio = MegaLights::GetGuideByHistoryHiddenRatio();
PassParameters->MegaLightsDepthHistory = SceneDepthHistory;
PassParameters->HistoryScreenPositionScaleBias = HistoryScreenPositionScaleBias;
PassParameters->HistoryUVMinMax = HistoryUVMinMax;
PassParameters->HistoryGatherUVMinMax = HistoryGatherUVMinMax;
PassParameters->HistoryBufferSizeAndInvSize = HistoryBufferSizeAndInvSize;
PassParameters->HistoryVisibleLightHashViewMinInTiles = HistoryVisibleLightHashViewMinInTiles;
PassParameters->HistoryVisibleLightHashViewSizeInTiles = HistoryVisibleLightHashViewSizeInTiles;
FGenerateLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FGenerateLightSamplesCS::FTileType>(TileType);
PermutationVector.Set<FGenerateLightSamplesCS::FNumSamplesPerPixel1d>(NumSamplesPerPixel2d.X * NumSamplesPerPixel2d.Y);
PermutationVector.Set<FGenerateLightSamplesCS::FGuideByHistory>(VisibleLightHashHistory != nullptr && SceneDepthHistory != nullptr);
PermutationVector.Set<FGenerateLightSamplesCS::FInputType>(uint32(InputType));
PermutationVector.Set<FGenerateLightSamplesCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FGenerateLightSamplesCS>(PermutationVector);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("GenerateSamples DownsampleFactor:%d SamplesPerPixel:%dx%d TileType:%s", DownsampleFactor, NumSamplesPerPixel2d.X, NumSamplesPerPixel2d.Y, MegaLights::GetTileTypeString((MegaLights::ETileType)TileType)),
ComputeShader,
PassParameters,
DownsampledTileIndirectArgs,
TileType * sizeof(FRHIDispatchIndirectParameters));
}
}
FRDGTextureRef VolumeLightSamples = nullptr;
if (MegaLights::UseVolume() && bShouldRenderVolumetricFog)
{
VolumeLightSamples = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create3D(VolumeSampleBufferSize, PF_R32_UINT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.Volume.LightSamples"));
// Generate new candidate light samples for the volume
{
FVolumeGenerateLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeGenerateLightSamplesCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->MegaLightsVolumeParameters = MegaLightsVolumeParameters;
PassParameters->VolumeVisibleLightHashHistory = VolumeVisibleLightHashHistory != nullptr ? GraphBuilder.CreateSRV(VolumeVisibleLightHashHistory) : nullptr;
PassParameters->RWVolumeLightSamples = GraphBuilder.CreateUAV(VolumeLightSamples);
PassParameters->HistoryVolumeVisibleLightHashViewSizeInTiles = HistoryVolumeVisibleLightHashViewSizeInTiles;
PassParameters->VolumeVisibleLightHashTileSize = VolumeVisibleLightHashTileSize;
PassParameters->VolumeGuideByHistoryHiddenRatio = MegaLightsVolume::GetGuideByHistoryHiddenRatio();
FVolumeGenerateLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FTranslucencyLightingVolume>(false);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FNumSamplesPerVoxel1d>(NumSamplesPerVoxel3d.X * NumSamplesPerVoxel3d.Y * NumSamplesPerVoxel3d.Z);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FLightSoftFading>(GetVolumetricFogLightSoftFading() > 0.0f);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FUseLightFunctionAtlas>(bUseLightFunctionAtlas && MegaLightsVolume::UsesLightFunction());
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FGuideByHistory>(VolumeVisibleLightHashHistory != nullptr);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FDebugMode>(bVolumeDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeGenerateLightSamplesCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(VolumeDownsampledViewSize, FVolumeGenerateLightSamplesCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("VolumeGenerateSamples SamplesPerVoxel:%dx%dx%d", NumSamplesPerVoxel3d.X, NumSamplesPerVoxel3d.Y, NumSamplesPerVoxel3d.Z),
ComputeShader,
PassParameters,
GroupCount);
}
}
TArray<FRDGTextureRef, TInlineAllocator<TVC_MAX>> TranslucencyVolumeLightSamples;
if (MegaLights::UseTranslucencyVolume() && bShouldRenderTranslucencyVolume)
{
TranslucencyVolumeLightSamples.AddDefaulted(TVC_MAX);
for (uint32 CascadeIndex = 0; CascadeIndex < TVC_MAX; ++CascadeIndex)
{
TranslucencyVolumeLightSamples[CascadeIndex] = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create3D(TranslucencyVolumeSampleBufferSize, PF_R32_UINT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.TranslucencyVolume.LightSamples"));
// Generate new candidate light samples for the Translucency Volume
{
FVolumeGenerateLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeGenerateLightSamplesCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->MegaLightsVolumeParameters = MegaLightsTranslucencyVolumeParameters;
PassParameters->MegaLightsVolumeParameters.TranslucencyVolumeCascadeIndex = CascadeIndex;
PassParameters->VolumeVisibleLightHashHistory = TranslucencyVolumeVisibleLightHashHistory[CascadeIndex] != nullptr ? GraphBuilder.CreateSRV(TranslucencyVolumeVisibleLightHashHistory[CascadeIndex]) : nullptr;
PassParameters->RWVolumeLightSamples = GraphBuilder.CreateUAV(TranslucencyVolumeLightSamples[CascadeIndex]);
PassParameters->HistoryVolumeVisibleLightHashViewSizeInTiles = HistoryTranslucencyVolumeVisibleLightHashSizeInTiles;
PassParameters->VolumeVisibleLightHashTileSize = TranslucencyVolumeVisibleLightHashTileSize;
PassParameters->VolumeGuideByHistoryHiddenRatio = MegaLightsTranslucencyVolume::GetGuideByHistoryHiddenRatio();
FVolumeGenerateLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FTranslucencyLightingVolume>(true);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FNumSamplesPerVoxel1d>(NumSamplesPerTranslucencyVoxel3d.X * NumSamplesPerTranslucencyVoxel3d.Y * NumSamplesPerTranslucencyVoxel3d.Z);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FLightSoftFading >(false);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FUseLightFunctionAtlas>(bUseLightFunctionAtlas && MegaLightsTranslucencyVolume::UsesLightFunction());
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FGuideByHistory>(TranslucencyVolumeVisibleLightHashHistory[CascadeIndex] != nullptr);
PermutationVector.Set<FVolumeGenerateLightSamplesCS::FDebugMode>(bTranslucencyVolumeDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeGenerateLightSamplesCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(TranslucencyVolumeDownsampledBufferSize, FVolumeGenerateLightSamplesCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("TranslucencyVolumeGenerateSamples SamplesPerVoxel:%dx%dx%d", NumSamplesPerTranslucencyVoxel3d.X, NumSamplesPerTranslucencyVoxel3d.Y, NumSamplesPerTranslucencyVoxel3d.Z),
ComputeShader,
PassParameters,
GroupCount);
}
}
}
MegaLights::RayTraceLightSamples(
ViewFamily,
View, ViewIndex,
GraphBuilder,
SceneTextures,
VirtualShadowMapArray,
SampleBufferSize,
LightSamples,
LightSampleRays,
VolumeSampleBufferSize,
VolumeLightSamples,
TranslucencyVolumeSampleBufferSize,
TranslucencyVolumeLightSamples,
MegaLightsParameters,
MegaLightsVolumeParameters,
MegaLightsTranslucencyVolumeParameters,
InputType
);
// Compute transmittance estimate for hair sample
FRDGTextureRef HairTransmittanceMaskTexture = nullptr;
if (InputType == EMegaLightsInput::HairStrands)
{
HairTransmittanceMaskTexture = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(DonwnsampledSampleBufferSize, PF_R32_UINT, FClearValueBinding::None, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.HairTransmittance"));
FMegaLightHairTransmittanceCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FMegaLightHairTransmittanceCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->VirtualVoxel = HairStrands::BindHairStrandsVoxelUniformParameters(View);
PassParameters->LightSamples = LightSamples;
PassParameters->LightSampleRays = LightSampleRays;
PassParameters->RWTransmittanceMaskTexture = GraphBuilder.CreateUAV(HairTransmittanceMaskTexture);
FMegaLightHairTransmittanceCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FMegaLightHairTransmittanceCS::FNumSamplesPerPixel1d>(NumSamplesPerPixel2d.X * NumSamplesPerPixel2d.Y);
auto ComputeShader = View.ShaderMap->GetShader<FMegaLightHairTransmittanceCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(DonwnsampledSampleBufferSize, FMegaLightHairTransmittanceCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("HairTransmittanceCS"),
ComputeShader,
PassParameters,
GroupCount);
}
FRDGTextureRef ResolvedDiffuseLighting = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(View.GetSceneTexturesConfig().Extent, PF_FloatRGB, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.ResolvedDiffuseLighting"));
FRDGTextureRef ResolvedSpecularLighting = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(View.GetSceneTexturesConfig().Extent, PF_FloatRGB, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.ResolvedSpecularLighting"));
FRDGTextureRef ShadingConfidence = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(View.GetSceneTexturesConfig().Extent, PF_R8, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.ShadingConfidence"));
FRDGBufferRef VisibleLightHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), VisibleLightHashBufferSize), TEXT("MegaLights.VisibleLightHash"));
FRDGBufferRef VisibleLightMaskHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), VisibleLightHashBufferSize), TEXT("MegaLights.VisibleLightMaskHash"));
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(VisibleLightHash), 0);
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(VisibleLightMaskHash), 0);
FRDGBufferRef VolumeVisibleLightHash = nullptr;
if (MegaLights::UseVolume() && bShouldRenderVolumetricFog && bVolumeGuideByHistory)
{
VolumeVisibleLightHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), VolumeVisibleLightHashBufferSize), TEXT("MegaLights.Volume.VisibleLightHash"));
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(VolumeVisibleLightHash), 0);
}
FRDGBufferRef TranslucencyVolumeVisibleLightHash[TVC_MAX] = {};
if (MegaLights::UseTranslucencyVolume() && bShouldRenderTranslucencyVolume && bTranslucencyVolumeGuideByHistory)
{
for (uint32 CascadeIndex = 0; CascadeIndex < TVC_MAX; ++CascadeIndex)
{
TranslucencyVolumeVisibleLightHash[CascadeIndex] = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), TranslucencyVolumeVisibleLightHashBufferSize), TEXT("MegaLights.TranslucencyVolume.VisibleLightHash"));
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(TranslucencyVolumeVisibleLightHash[CascadeIndex]), 0);
}
}
// Shade light samples
{
FRDGTextureUAVRef ResolvedDiffuseLightingUAV = GraphBuilder.CreateUAV(ResolvedDiffuseLighting, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGTextureUAVRef ResolvedSpecularLightingUAV = GraphBuilder.CreateUAV(ResolvedSpecularLighting, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGTextureUAVRef ShadingConfidenceUAV = GraphBuilder.CreateUAV(ShadingConfidence, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGBufferUAVRef VisibleLightHashUAV = GraphBuilder.CreateUAV(VisibleLightHash, ERDGUnorderedAccessViewFlags::SkipBarrier);
FRDGBufferUAVRef VisibleLightMaskHashUAV = GraphBuilder.CreateUAV(VisibleLightMaskHash, ERDGUnorderedAccessViewFlags::SkipBarrier);
// Clear tiles which won't be processed by FShadeLightSamplesCS
{
FClearResolvedLightingCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FClearResolvedLightingCS::FParameters>();
PassParameters->IndirectArgs = TileIndirectArgs;
PassParameters->RWResolvedDiffuseLighting = ResolvedDiffuseLightingUAV;
PassParameters->RWResolvedSpecularLighting = ResolvedSpecularLightingUAV;
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->TileAllocator = GraphBuilder.CreateSRV(TileAllocator);
PassParameters->TileData = GraphBuilder.CreateSRV(TileData);
auto ComputeShader = View.ShaderMap->GetShader<FClearResolvedLightingCS>();
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("ClearResolvedLighting"),
ComputeShader,
PassParameters,
TileIndirectArgs,
(int32)MegaLights::ETileType::Empty * sizeof(FRHIDispatchIndirectParameters));
}
for (const int32 TileType : ShadingTileTypes)
{
if (!View.bLightGridHasRectLights && IsRectLightTileType((MegaLights::ETileType)TileType))
{
continue;
}
if (!View.bLightGridHasTexturedLights && IsTexturedLightTileType((MegaLights::ETileType)TileType))
{
continue;
}
FShadeLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FShadeLightSamplesCS::FParameters>();
PassParameters->RWResolvedDiffuseLighting = ResolvedDiffuseLightingUAV;
PassParameters->RWResolvedSpecularLighting = ResolvedSpecularLightingUAV;
PassParameters->RWShadingConfidence = ShadingConfidenceUAV;
PassParameters->IndirectArgs = TileIndirectArgs;
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->TileAllocator = GraphBuilder.CreateSRV(TileAllocator);
PassParameters->TileData = GraphBuilder.CreateSRV(TileData);
PassParameters->LightSamples = LightSamples;
PassParameters->UseShadingConfidence = CVarMegaLightsShadingConfidence.GetValueOnRenderThread();
PassParameters->HairTransmittanceMaskTexture = HairTransmittanceMaskTexture;
FShadeLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FShadeLightSamplesCS::FTileType>(TileType);
PermutationVector.Set<FShadeLightSamplesCS::FDownsampleFactor>(DownsampleFactor);
PermutationVector.Set<FShadeLightSamplesCS::FNumSamplesPerPixel1d>(NumSamplesPerPixel2d.X * NumSamplesPerPixel2d.Y);
PermutationVector.Set<FShadeLightSamplesCS::FInputType>(uint32(InputType));
PermutationVector.Set<FShadeLightSamplesCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FShadeLightSamplesCS>(PermutationVector);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("ShadeLightSamples TileType:%s", MegaLights::GetTileTypeString((MegaLights::ETileType)TileType)),
ComputeShader,
PassParameters,
TileIndirectArgs,
TileType * sizeof(FRHIDispatchIndirectParameters));
}
}
// Prepare visible light list hash for the next frame
if (bGuideByHistory)
{
FVisibleLightHashCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVisibleLightHashCS::FParameters>();
PassParameters->RWVisibleLightHash = GraphBuilder.CreateUAV(VisibleLightHash);
PassParameters->RWVisibleLightMaskHash = GraphBuilder.CreateUAV(VisibleLightMaskHash);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->LightSamples = LightSamples;
PassParameters->LightSampleRays = LightSampleRays;
FVisibleLightHashCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVisibleLightHashCS::FNumSamplesPerPixel1d>(NumSamplesPerPixel2d.X * NumSamplesPerPixel2d.Y);
PermutationVector.Set<FVisibleLightHashCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVisibleLightHashCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(View.ViewRect.Size(), FVisibleLightHashCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("VisibleLightHash"),
ComputeShader,
PassParameters,
GroupCount);
}
if (MegaLights::UseVolume() && bShouldRenderVolumetricFog && bVolumeGuideByHistory)
{
FVolumeVisibleLightHashCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeVisibleLightHashCS::FParameters>();
PassParameters->RWVisibleLightHash = GraphBuilder.CreateUAV(VolumeVisibleLightHash);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->LightSamples = VolumeLightSamples;
PassParameters->VolumeVisibleLightHashTileSize = VolumeVisibleLightHashTileSize;
PassParameters->VolumeVisibleLightHashViewSizeInTiles = VolumeVisibleLightHashViewSizeInTiles;
FVolumeVisibleLightHashCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeVisibleLightHashCS::FNumSamplesPerVoxel1d>(NumSamplesPerVoxel3d.X * NumSamplesPerVoxel3d.Y * NumSamplesPerVoxel3d.Z);
PermutationVector.Set<FVolumeVisibleLightHashCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeVisibleLightHashCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(VolumeVisibleLightHashViewSizeInTiles, FVolumeVisibleLightHashCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("VolumeVisibleLightHash"),
ComputeShader,
PassParameters,
GroupCount);
}
if (MegaLights::UseTranslucencyVolume() && bShouldRenderTranslucencyVolume && bTranslucencyVolumeGuideByHistory)
{
for (uint32 CascadeIndex = 0; CascadeIndex < TVC_MAX; ++CascadeIndex)
{
FVolumeVisibleLightHashCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeVisibleLightHashCS::FParameters>();
PassParameters->RWVisibleLightHash = GraphBuilder.CreateUAV(TranslucencyVolumeVisibleLightHash[CascadeIndex]);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->LightSamples = TranslucencyVolumeLightSamples[CascadeIndex];
PassParameters->VolumeVisibleLightHashTileSize = TranslucencyVolumeVisibleLightHashTileSize;
PassParameters->VolumeVisibleLightHashViewSizeInTiles = TranslucencyVolumeVisibleLightHashSizeInTiles;
FVolumeVisibleLightHashCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeVisibleLightHashCS::FNumSamplesPerVoxel1d>(NumSamplesPerTranslucencyVoxel3d.X * NumSamplesPerTranslucencyVoxel3d.Y * NumSamplesPerTranslucencyVoxel3d.Z);
PermutationVector.Set<FVolumeVisibleLightHashCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeVisibleLightHashCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(TranslucencyVolumeVisibleLightHashSizeInTiles, FVolumeVisibleLightHashCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("TranslucencyVolumeVisibleLightHash"),
ComputeShader,
PassParameters,
GroupCount);
}
}
if (MegaLights::UseVolume() && bShouldRenderVolumetricFog)
{
FRDGTextureRef VolumeResolvedLighting = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create3D(VolumeBufferSize, PF_FloatRGB, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.Volume.ResolvedLighting"));
FVolumeShadeLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeShadeLightSamplesCS::FParameters>();
PassParameters->RWVolumeResolvedLighting = GraphBuilder.CreateUAV(VolumeResolvedLighting);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->MegaLightsVolumeParameters = MegaLightsVolumeParameters;
PassParameters->VolumeLightSamples = VolumeLightSamples;
FVolumeShadeLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeShadeLightSamplesCS::FTranslucencyLightingVolume>(false);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FDownsampleFactor>(VolumeDownsampleFactor);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FNumSamplesPerVoxel1d>(NumSamplesPerVoxel3d.X * NumSamplesPerVoxel3d.Y * NumSamplesPerVoxel3d.Z);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FLightSoftFading>(GetVolumetricFogLightSoftFading() > 0.0f);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FUseLightFunctionAtlas >(bUseLightFunctionAtlas && MegaLightsVolume::UsesLightFunction());
PermutationVector.Set<FVolumeShadeLightSamplesCS::FDebugMode>(bVolumeDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeShadeLightSamplesCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(VolumeViewSize, FVolumeShadeLightSamplesCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("VolumeShadeLightSamples"),
ComputeShader,
PassParameters,
GroupCount);
if (MegaLightsVolume)
{
MegaLightsVolume->Texture = VolumeResolvedLighting;
}
}
if (MegaLights::UseTranslucencyVolume() && bShouldRenderTranslucencyVolume)
{
for (uint32 CascadeIndex = 0; CascadeIndex < TVC_MAX; ++CascadeIndex)
{
FRDGTextureRef TranslucencyVolumeResolvedLightingAmbient = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create3D(TranslucencyVolumeBufferSize, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.TranslucencyVolume.ResolvedLightingAmbient"));
FRDGTextureRef TranslucencyVolumeResolvedLightingDirectional = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create3D(TranslucencyVolumeBufferSize, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.TranslucencyVolume.ResolvedLightingDirectional"));
FVolumeShadeLightSamplesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeShadeLightSamplesCS::FParameters>();
PassParameters->RWTranslucencyVolumeResolvedLightingAmbient = GraphBuilder.CreateUAV(TranslucencyVolumeResolvedLightingAmbient);
PassParameters->RWTranslucencyVolumeResolvedLightingDirectional = GraphBuilder.CreateUAV(TranslucencyVolumeResolvedLightingDirectional);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->MegaLightsVolumeParameters = MegaLightsTranslucencyVolumeParameters;
PassParameters->MegaLightsVolumeParameters.TranslucencyVolumeCascadeIndex = CascadeIndex;
PassParameters->VolumeLightSamples = TranslucencyVolumeLightSamples[CascadeIndex];
FVolumeShadeLightSamplesCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeShadeLightSamplesCS::FTranslucencyLightingVolume>(true);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FDownsampleFactor>(TranslucencyVolumeDownsampleFactor);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FNumSamplesPerVoxel1d>(NumSamplesPerTranslucencyVoxel3d.X * NumSamplesPerTranslucencyVoxel3d.Y * NumSamplesPerTranslucencyVoxel3d.Z);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FLightSoftFading>(false);
PermutationVector.Set<FVolumeShadeLightSamplesCS::FUseLightFunctionAtlas >(bUseLightFunctionAtlas && MegaLightsTranslucencyVolume::UsesLightFunction());
PermutationVector.Set<FVolumeShadeLightSamplesCS::FDebugMode>(bTranslucencyVolumeDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeShadeLightSamplesCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(TranslucencyVolumeBufferSize, FVolumeShadeLightSamplesCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("TranslucencyVolumeShadeLightSamples"),
ComputeShader,
PassParameters,
GroupCount);
if (MegaLightsVolume)
{
MegaLightsVolume->TranslucencyAmbient[CascadeIndex] = TranslucencyVolumeResolvedLightingAmbient;
MegaLightsVolume->TranslucencyDirectional[CascadeIndex] = TranslucencyVolumeResolvedLightingDirectional;
}
}
}
if (bGuideByHistory && CVarMegaLightsGuideByHistoryFilter.GetValueOnRenderThread())
{
FRDGBufferRef FilteredVisibleLightHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), VisibleLightHashBufferSize), TEXT("MegaLights.FilteredVisibleLightHash"));
FRDGBufferRef FilteredVisibleLightMaskHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), VisibleLightHashBufferSize), TEXT("MegaLights.FilteredVisibleLightMaskHash"));
FFilterVisibleLightHashCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FFilterVisibleLightHashCS::FParameters>();
PassParameters->RWVisibleLightHash = GraphBuilder.CreateUAV(FilteredVisibleLightHash);
PassParameters->RWVisibleLightMaskHash = GraphBuilder.CreateUAV(FilteredVisibleLightMaskHash);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->VisibleLightHashBuffer = GraphBuilder.CreateSRV(VisibleLightHash);
PassParameters->VisibleLightMaskHashBuffer = GraphBuilder.CreateSRV(VisibleLightMaskHash);
FFilterVisibleLightHashCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FFilterVisibleLightHashCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FFilterVisibleLightHashCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(VisibleLightHashViewSizeInTiles, FFilterVisibleLightHashCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("FilterVisibleLightHash"),
ComputeShader,
PassParameters,
GroupCount);
VisibleLightHash = FilteredVisibleLightHash;
VisibleLightMaskHash = FilteredVisibleLightMaskHash;
}
if (MegaLights::UseVolume() && bShouldRenderVolumetricFog && bVolumeGuideByHistory && CVarMegaLightsVolumeGuideByHistoryFilter.GetValueOnRenderThread())
{
FRDGBufferRef VolumeFilteredVisibleLightHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), VolumeVisibleLightHashBufferSize), TEXT("MegaLights.Volume.FilteredVisibleLightHash"));
FVolumeFilterVisibleLightHashCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeFilterVisibleLightHashCS::FParameters>();
PassParameters->RWVisibleLightHash = GraphBuilder.CreateUAV(VolumeFilteredVisibleLightHash);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->VolumeVisibleLightHashViewSizeInTiles = VolumeVisibleLightHashViewSizeInTiles;
PassParameters->VisibleLightHashBuffer = GraphBuilder.CreateSRV(VolumeVisibleLightHash);
FVolumeFilterVisibleLightHashCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeFilterVisibleLightHashCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeFilterVisibleLightHashCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(VolumeVisibleLightHashViewSizeInTiles, FVolumeFilterVisibleLightHashCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("VolumeFilterVisibleLightHash"),
ComputeShader,
PassParameters,
GroupCount);
VolumeVisibleLightHash = VolumeFilteredVisibleLightHash;
}
if (MegaLights::UseTranslucencyVolume() && bShouldRenderTranslucencyVolume && bTranslucencyVolumeGuideByHistory && CVarMegaLightsTranslucencyVolumeGuideByHistoryFilter.GetValueOnRenderThread())
{
for (uint32 CascadeIndex = 0; CascadeIndex < TVC_MAX; ++CascadeIndex)
{
FRDGBufferRef TranslucencyVolumeFilteredVisibleLightHash = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), TranslucencyVolumeVisibleLightHashBufferSize), TEXT("MegaLights.TranslucencyVolume.FilteredVisibleLightHash"));
FVolumeFilterVisibleLightHashCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVolumeFilterVisibleLightHashCS::FParameters>();
PassParameters->RWVisibleLightHash = GraphBuilder.CreateUAV(TranslucencyVolumeFilteredVisibleLightHash);
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->VolumeVisibleLightHashViewSizeInTiles = TranslucencyVolumeVisibleLightHashSizeInTiles;
PassParameters->VisibleLightHashBuffer = GraphBuilder.CreateSRV(TranslucencyVolumeVisibleLightHash[CascadeIndex]);
FVolumeFilterVisibleLightHashCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FVolumeFilterVisibleLightHashCS::FDebugMode>(bDebug);
auto ComputeShader = View.ShaderMap->GetShader<FVolumeFilterVisibleLightHashCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(TranslucencyVolumeVisibleLightHashSizeInTiles, FVolumeFilterVisibleLightHashCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("TranslucencyVolumeFilterVisibleLightHash"),
ComputeShader,
PassParameters,
GroupCount);
TranslucencyVolumeVisibleLightHash[CascadeIndex] = TranslucencyVolumeFilteredVisibleLightHash;
}
}
// Demodulated lighting components with second luminance moments stored in alpha channel for temporal variance tracking
// This will be passed to the next frame
FRDGTextureRef DiffuseLightingAndSecondMoment = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(View.GetSceneTexturesConfig().Extent, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.DiffuseLightingAndSecondMoment"));
FRDGTextureRef SpecularLightingAndSecondMoment = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(View.GetSceneTexturesConfig().Extent, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.SpecularLightingAndSecondMoment"));
FRDGTextureRef NumFramesAccumulated = GraphBuilder.CreateTexture(
FRDGTextureDesc::Create2D(View.GetSceneTexturesConfig().Extent, PF_G8, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV),
TEXT("MegaLights.NumFramesAccumulated"));
// Temporal accumulation
{
FDenoiserTemporalCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDenoiserTemporalCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->ResolvedDiffuseLighting = ResolvedDiffuseLighting;
PassParameters->ResolvedSpecularLighting = ResolvedSpecularLighting;
PassParameters->ShadingConfidenceTexture = ShadingConfidence;
PassParameters->DiffuseLightingAndSecondMomentHistoryTexture = DiffuseLightingAndSecondMomentHistory;
PassParameters->SpecularLightingAndSecondMomentHistoryTexture = SpecularLightingAndSecondMomentHistory;
PassParameters->NumFramesAccumulatedHistoryTexture = NumFramesAccumulatedHistory;
PassParameters->MegaLightsDepthHistory = SceneDepthHistory;
PassParameters->MegaLightsNormalAndShading = SceneNormalAndShadingHistory;
PassParameters->PrevSceneColorPreExposureCorrection = View.PreExposure / View.PrevViewInfo.SceneColorPreExposure;
PassParameters->MinFramesAccumulatedForHistoryMiss = FMath::Clamp(CVarMegaLightsTemporalMinFramesAccumulatedForHistoryMiss.GetValueOnRenderThread(), 1.0f, MegaLights::GetTemporalMaxFramesAccumulated());
PassParameters->MinFramesAccumulatedForHighConfidence = FMath::Clamp(CVarMegaLightsTemporalMinFramesAccumulatedForHighConfidence.GetValueOnRenderThread(), 1.0f, MegaLights::GetTemporalMaxFramesAccumulated());
PassParameters->HistoryScreenPositionScaleBias = HistoryScreenPositionScaleBias;
PassParameters->HistoryUVMinMax = HistoryUVMinMax;
PassParameters->HistoryGatherUVMinMax = HistoryGatherUVMinMax;
PassParameters->HistoryBufferSizeAndInvSize = HistoryBufferSizeAndInvSize;
PassParameters->RWDiffuseLightingAndSecondMoment = GraphBuilder.CreateUAV(DiffuseLightingAndSecondMoment);
PassParameters->RWSpecularLightingAndSecondMoment = GraphBuilder.CreateUAV(SpecularLightingAndSecondMoment);
PassParameters->RWNumFramesAccumulated = GraphBuilder.CreateUAV(NumFramesAccumulated);
FDenoiserTemporalCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FDenoiserTemporalCS::FValidHistory>(DiffuseLightingAndSecondMomentHistory && SceneDepthHistory && SceneNormalAndShadingHistory && bTemporal);
PermutationVector.Set<FDenoiserTemporalCS::FDebugMode>(bDebug);
PermutationVector.Set<FDenoiserTemporalCS::FInputType>(uint32(InputType));
auto ComputeShader = View.ShaderMap->GetShader<FDenoiserTemporalCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(View.ViewRect.Size(), FDenoiserTemporalCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("TemporalAccumulation"),
ComputeShader,
PassParameters,
GroupCount);
}
// Spatial filter
{
FDenoiserSpatialCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDenoiserSpatialCS::FParameters>();
PassParameters->MegaLightsParameters = MegaLightsParameters;
PassParameters->RWSceneColor = GraphBuilder.CreateUAV(OutputColorTarget);
PassParameters->DiffuseLightingAndSecondMomentTexture = DiffuseLightingAndSecondMoment;
PassParameters->SpecularLightingAndSecondMomentTexture = SpecularLightingAndSecondMoment;
PassParameters->ShadingConfidenceTexture = ShadingConfidence;
PassParameters->NumFramesAccumulatedTexture = NumFramesAccumulated;
PassParameters->SpatialFilterDepthWeightScale = CVarMegaLightsSpatialDepthWeightScale.GetValueOnRenderThread();
PassParameters->SpatialFilterKernelRadius = CVarMegaLightsSpatialKernelRadius.GetValueOnRenderThread();
PassParameters->SpatialFilterNumSamples = FMath::Clamp(CVarMegaLightsSpatialNumSamples.GetValueOnRenderThread(), 0, 1024);
PassParameters->SpatialFilterMaxDisocclusionFrames = MegaLights::GetSpatialFilterMaxDisocclusionFrames();
FDenoiserSpatialCS::FPermutationDomain PermutationVector;
PermutationVector.Set<FDenoiserSpatialCS::FSpatialFilter>(bSpatial);
PermutationVector.Set<FDenoiserSpatialCS::FDebugMode>(bDebug);
PermutationVector.Set<FDenoiserSpatialCS::FInputType>(uint32(InputType));
auto ComputeShader = View.ShaderMap->GetShader<FDenoiserSpatialCS>(PermutationVector);
const FIntVector GroupCount = FComputeShaderUtils::GetGroupCount(View.ViewRect.Size(), FDenoiserSpatialCS::GetGroupSize());
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("Spatial"),
ComputeShader,
PassParameters,
GroupCount);
}
if (View.ViewState && !View.bStatePrevViewInfoIsReadOnly)
{
FMegaLightsViewState& MegaLightsViewState = View.ViewState->MegaLights;
MegaLightsViewState.HistoryScreenPositionScaleBias = View.GetScreenPositionScaleBias(View.GetSceneTexturesConfig().Extent, View.ViewRect);
const FVector2f InvBufferSize(1.0f / SceneTextures.Config.Extent.X, 1.0f / SceneTextures.Config.Extent.Y);
MegaLightsViewState.HistoryUVMinMax = FVector4f(
View.ViewRect.Min.X * InvBufferSize.X,
View.ViewRect.Min.Y * InvBufferSize.Y,
View.ViewRect.Max.X * InvBufferSize.X,
View.ViewRect.Max.Y * InvBufferSize.Y);
// Clamp gather4 to a valid bilinear footprint in order to avoid sampling outside of valid bounds
MegaLightsViewState.HistoryGatherUVMinMax = FVector4f(
(View.ViewRect.Min.X + 0.51f) * InvBufferSize.X,
(View.ViewRect.Min.Y + 0.51f) * InvBufferSize.Y,
(View.ViewRect.Max.X - 0.51f) * InvBufferSize.X,
(View.ViewRect.Max.Y - 0.51f) * InvBufferSize.Y);
MegaLightsViewState.HistoryBufferSizeAndInvSize = FVector4f(
SceneTextures.Config.Extent.X,
SceneTextures.Config.Extent.Y,
1.0f / SceneTextures.Config.Extent.X,
1.0f / SceneTextures.Config.Extent.Y);
MegaLightsViewState.HistoryVisibleLightHashViewMinInTiles = VisibleLightHashViewMinInTiles;
MegaLightsViewState.HistoryVisibleLightHashViewSizeInTiles = VisibleLightHashViewSizeInTiles;
MegaLightsViewState.HistoryVolumeVisibleLightHashViewSizeInTiles = VolumeVisibleLightHashViewSizeInTiles;
MegaLightsViewState.HistoryTranslucencyVolumeVisibleLightHashSizeInTiles = TranslucencyVolumeVisibleLightHashSizeInTiles;
if (DiffuseLightingAndSecondMoment && SpecularLightingAndSecondMoment && NumFramesAccumulated && bTemporal)
{
GraphBuilder.QueueTextureExtraction(DiffuseLightingAndSecondMoment, &MegaLightsViewState.DiffuseLightingAndSecondMomentHistory);
GraphBuilder.QueueTextureExtraction(SpecularLightingAndSecondMoment, &MegaLightsViewState.SpecularLightingAndSecondMomentHistory);
GraphBuilder.QueueTextureExtraction(NumFramesAccumulated, &MegaLightsViewState.NumFramesAccumulatedHistory);
}
else
{
MegaLightsViewState.DiffuseLightingAndSecondMomentHistory = nullptr;
MegaLightsViewState.SpecularLightingAndSecondMomentHistory = nullptr;
MegaLightsViewState.NumFramesAccumulatedHistory = nullptr;
}
if (bGuideByHistory)
{
GraphBuilder.QueueBufferExtraction(VisibleLightHash, &MegaLightsViewState.VisibleLightHashHistory);
GraphBuilder.QueueBufferExtraction(VisibleLightMaskHash, &MegaLightsViewState.VisibleLightMaskHashHistory);
}
else
{
MegaLightsViewState.VisibleLightHashHistory = nullptr;
MegaLightsViewState.VisibleLightMaskHashHistory = nullptr;
}
if (bVolumeGuideByHistory && VolumeVisibleLightHash != nullptr)
{
GraphBuilder.QueueBufferExtraction(VolumeVisibleLightHash, &MegaLightsViewState.VolumeVisibleLightHashHistory);
}
else
{
MegaLightsViewState.VolumeVisibleLightHashHistory = nullptr;
}
if (bTranslucencyVolumeGuideByHistory && TranslucencyVolumeVisibleLightHash[0] != nullptr && TranslucencyVolumeVisibleLightHash[1] != nullptr)
{
GraphBuilder.QueueBufferExtraction(TranslucencyVolumeVisibleLightHash[0], &MegaLightsViewState.TranslucencyVolume0VisibleLightHashHistory);
GraphBuilder.QueueBufferExtraction(TranslucencyVolumeVisibleLightHash[1], &MegaLightsViewState.TranslucencyVolume1VisibleLightHashHistory);
}
else
{
MegaLightsViewState.TranslucencyVolume0VisibleLightHashHistory = nullptr;
MegaLightsViewState.TranslucencyVolume1VisibleLightHashHistory = nullptr;
}
}
}
}
void FDeferredShadingSceneRenderer::RenderMegaLights(FRDGBuilder& GraphBuilder, const FSceneTextures& SceneTextures, FRDGTextureRef LightingChannelsTexture, const FSortedLightSetSceneInfo& SortedLightSet)
{
if (!MegaLights::IsEnabled(ViewFamily) || !ViewFamily.EngineShowFlags.DirectLighting)
{
return;
}
check(AreLightsInLightGrid());
RDG_EVENT_SCOPE_STAT(GraphBuilder, MegaLights, "MegaLights");
RDG_GPU_STAT_SCOPE(GraphBuilder, MegaLights);
FBlueNoise BlueNoise = GetBlueNoiseGlobalParameters();
TUniformBufferRef<FBlueNoise> BlueNoiseUniformBuffer = CreateUniformBufferImmediate(BlueNoise, EUniformBufferUsage::UniformBuffer_SingleDraw);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
// Enable support for VSMs if there are any relevant local lights and the feature is enabled
FShadowSceneRenderer& ShadowSceneRenderer = GetSceneExtensionsRenderers().GetRenderer<FShadowSceneRenderer>();
const bool bUseVSM = VirtualShadowMapArray.IsAllocated() && ShadowSceneRenderer.AreAnyLightsUsingMegaLightsVSM();
const bool bHairStrands = HairStrands::HasViewHairStrandsData(View) && CVarMegaLightsEnableHairStrands.GetValueOnRenderThread() > 0;
{
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, bHairStrands, "GBuffer");
InternalRenderMegaLights(
GraphBuilder,
ViewIndex,
View,
ViewFamily,
Scene,
SceneTextures,
LightingChannelsTexture,
SortedLightSet,
bUseVSM ? &VirtualShadowMapArray : nullptr,
&View.GetOwnMegaLightsVolume(),
ShouldRenderVolumetricFog(),
MegaLights::UseTranslucencyVolume(),
BlueNoiseUniformBuffer,
EMegaLightsInput::GBuffer,
SceneTextures.Color.Target);
}
if (bHairStrands)
{
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, bHairStrands, "HairStrands");
InternalRenderMegaLights(
GraphBuilder,
ViewIndex,
View,
ViewFamily,
Scene,
SceneTextures,
LightingChannelsTexture,
SortedLightSet,
bUseVSM ? &VirtualShadowMapArray : nullptr,
nullptr /*MegaLightsVolume*/,
false /*bShouldRenderVolumetricFog*/,
false /*bShouldRenderTranslucencyVolume*/,
BlueNoiseUniformBuffer,
EMegaLightsInput::HairStrands,
View.HairStrandsViewData.VisibilityData.SampleLightingTexture);
}
}
}
namespace MegaLights
{
bool IsMissingDirectionalLightData(const FSceneViewFamily& ViewFamily)
{
static auto LightBufferModeCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Forward.LightBuffer.Mode"));
return CVarMegaLightsDirectionalLights.GetValueOnRenderThread() && LightBufferModeCVar->GetInt() == 0;
}
bool HasWarning(const FSceneViewFamily& ViewFamily)
{
return IsRequested(ViewFamily) && (!HasRequiredTracingData(ViewFamily) || IsMissingDirectionalLightData(ViewFamily));
}
void WriteWarnings(const FSceneViewFamily& ViewFamily, FScreenMessageWriter& Writer)
{
if (!HasWarning(ViewFamily))
{
return;
}
if (!HasRequiredTracingData(ViewFamily))
{
static const FText MainMessage = NSLOCTEXT("Renderer", "MegaLightsCantDisplay", "MegaLights is enabled, but has no ray tracing data and won't operate correctly.");
Writer.DrawLine(MainMessage);
#if RHI_RAYTRACING
if (!IsRayTracingAllowed())
{
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToHWRTNotAllowed", "- Hardware Ray Tracing is not allowed. Check log for more info.");
Writer.DrawLine(Message);
}
else if (!IsRayTracingEnabled())
{
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToHWRTDisabled", "- Enable 'r.RayTracing.Enable'.");
Writer.DrawLine(Message);
}
static auto CVarMegaLightsHardwareRayTracing = IConsoleManager::Get().FindConsoleVariable(TEXT("r.MegaLights.HardwareRayTracing"));
if (CVarMegaLightsHardwareRayTracing->GetInt() == 0)
{
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToCvar", "- Enable 'r.MegaLights.HardwareRayTracing'.");
Writer.DrawLine(Message);
}
static auto CVarMegaLightsHardwareRayTracingInline = IConsoleManager::Get().FindConsoleVariable(TEXT("r.MegaLights.HardwareRayTracing.Inline"));
if (!(GRHISupportsRayTracingShaders || (GRHISupportsInlineRayTracing && CVarMegaLightsHardwareRayTracingInline->GetInt() != 0)))
{
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToPlatformSettings", "- Enable Full Ray Tracing in platform platform settings or r.MegaLights.HardwareRayTracing.Inline.");
Writer.DrawLine(Message);
}
if (!(ViewFamily.Views.Num() == 1 || (ViewFamily.Views.Num() == 2 && IStereoRendering::IsStereoEyeView(*ViewFamily.Views[0]))))
{
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToMultipleViews", "- Multiple views are not supported.");
Writer.DrawLine(Message);
}
if (!ViewFamily.Views[0]->IsRayTracingAllowedForView())
{
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToView", "- Ray Tracing not allowed on the View.");
Writer.DrawLine(Message);
}
#else
static const FText Message = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDueToBuild", "- Unreal Engine was built without Hardware Ray Tracing support.");
Writer.DrawLine(Message);
#endif
}
if (IsMissingDirectionalLightData(ViewFamily))
{
static const FText MainMessage = NSLOCTEXT("Renderer", "MegaLightsCantDisplayDirectionalLights", "MegaLights requires r.Forward.LightBuffer.Mode > 0 when using r.MegaLights.DirectionalLights=1.");
Writer.DrawLine(MainMessage);
}
}
}