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

162 lines
5.4 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../Common.ush"
#include "../BlueNoise.ush"
#include "../SceneTexturesCommon.ush"
#include "../LightData.ush"
#include "../VirtualShadowMaps/VirtualShadowMapProjectionCommon.ush"
#include "../VirtualShadowMaps/VirtualShadowMapProjectionSpot.ush"
#include "../VirtualShadowMaps/VirtualShadowMapProjectionDirectional.ush"
#include "../VirtualShadowMaps/VirtualShadowMapScreenRayTrace.ush"
#include "MegaLights.ush"
#include "MegaLightsRayTracing.ush"
RWTexture2D<uint> RWLightSamples;
RWTexture2D<uint> RWLightSampleRays;
Buffer<uint> CompactedTraceTexelAllocator;
Buffer<uint> CompactedTraceTexelData;
Texture2D<float> DownsampledSceneDepth;
Texture2D<UNORM float3> DownsampledSceneWorldNormal;
SCHEDULER_MIN_PRESSURE
// Avoid for now due to issues with failing compilation when occupancy not reached
//MAX_OCCUPANCY
[numthreads(THREADGROUP_SIZE, 1, 1)]
void VirtualShadowMapTraceLightSamplesCS(
uint3 GroupId : SV_GroupID,
uint3 GroupThreadId : SV_GroupThreadID,
uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint TraceTexelIndex = DispatchThreadId.x;
if (TraceTexelIndex < CompactedTraceTexelAllocator[0])
{
const uint2 SampleCoord = UnpackTraceTexel(CompactedTraceTexelData[TraceTexelIndex]);
FLightSample LightSample = UnpackLightSample(RWLightSamples[SampleCoord]);
// Get VSM from LocalLightIndex
const FForwardLightData ForwardLightData = GetForwardLightData(LightSample.LocalLightIndex, 0);
const int VirtualShadowMapId = ForwardLightData.VirtualShadowMapId;
// Should we select for this separately in the tile classification instead?
if (VirtualShadowMapId != INDEX_NONE)
{
const FDeferredLightData LightData = ConvertToDeferredLight(ForwardLightData);
uint2 ScreenCoord = SampleCoordToScreenCoord(SampleCoord);
uint2 DownsampledScreenCoord = SampleCoordToDownsampledScreenCoord(SampleCoord);
float2 ScreenUV = (ScreenCoord + 0.5f) * View.BufferSizeAndInvSize.zw;
float SceneDepth = DownsampledSceneDepth[DownsampledScreenCoord];
float3 SceneWorldNormal = normalize(DecodeNormal(DownsampledSceneWorldNormal[DownsampledScreenCoord]));
float3 TranslatedWorldPosition = GetTranslatedWorldPositionFromScreenUV(ScreenUV, SceneDepth);
bool bDirectionalLight = !LightData.bRadialLight;
const float3 ToLightDirection =
bDirectionalLight ?
LightData.Direction :
normalize(LightData.TranslatedWorldPosition - TranslatedWorldPosition);
// Currently using the embedded SMRT ray sampling; could change this to use this one easily if needed
//FLightSampleTrace LightSampleTrace = GetLightSampleTrace(TranslatedWorldPosition, LightSample.LocalLightIndex, SampleCoord);
float StepOffset = BlueNoiseScalar(DownsampledScreenCoord, MegaLightsStateFrameIndex);
const float ScreenRayLengthWorld = GetScreenRayLengthMultiplierForProjectionType(VirtualShadowMap.ScreenRayLength * SceneDepth).y;
// TODO: Avoid doing this normal bias for subsurface pixels
// Will need to consider both substrate and downsampling
//if (!ShadingInfo.bIsSubsurface)
{
TranslatedWorldPosition += SceneWorldNormal * VirtualShadowMapGetNormalBiasLength(TranslatedWorldPosition);
}
// VSM screen ray trace
float RayStartOffset = ScreenRayLengthWorld;
if (ScreenRayLengthWorld > 0.0f)
{
RayStartOffset = VirtualShadowMapScreenRayCast(
TranslatedWorldPosition,
ToLightDirection,
ScreenRayLengthWorld,
StepOffset);
}
// TODO: Back-facing tests? (or BRDF test directly?)
// In MegaLights this is already factored into the sample selection though, so less important
#if 0
FVirtualShadowMapSampleResult VSMResult = SampleVirtualShadowMapLocal(
VirtualShadowMapId,
TranslatedWorldPosition,
RayStartOffset,
SceneWorldNormal
);
if (!VSMResult.bValid || VSMResult.ShadowFactor < 0.5f)
{
LightSample.bVisible = false;
}
#else
FLightShaderParameters LightParameters = ConvertFromForward(ForwardLightData);
FVirtualShadowMapSampleResult Result;
// TODO: Possibly worth a permutation for register pressure reasons
if (bDirectionalLight)
{
FSMRTTraceSettings Settings = GetSMRTTraceSettingsDirectional();
// Certain settings may be less desirable with the MegaLights path, but since there
// is typically only one directional light, it makes sense to respect the cvars
// which can be set up as desired for this path.
//Settings.RayCount = 1;
//Settings.AdaptiveRayCount = 0;
Result = TraceDirectional(
VirtualShadowMapId,
LightParameters,
SampleCoord,
SceneDepth,
TranslatedWorldPosition,
RayStartOffset,
StepOffset,
SceneWorldNormal,
Settings);
}
else
{
FSMRTTraceSettings Settings = GetSMRTTraceSettingsLocal();
Settings.RayCount = 1;
Settings.AdaptiveRayCount = 0;
Result = TraceLocalLight(
VirtualShadowMapId,
LightParameters,
SampleCoord,
SceneDepth,
TranslatedWorldPosition,
RayStartOffset,
StepOffset,
SceneWorldNormal,
Settings
);
}
if (!Result.bValid || Result.ShadowFactor < 0.5f)
{
LightSample.bVisible = false;
}
#endif
// Mark sample as complete to skip continuation
FLightSampleRay LightSampleRay = UnpackLightSampleRay(RWLightSampleRays[SampleCoord]);
LightSampleRay.bCompleted = true;
RWLightSampleRays[SampleCoord] = PackLightSampleRay(LightSampleRay);
RWLightSamples[SampleCoord] = PackLightSample(LightSample);
}
}
}