Files
UnrealEngineUWP/Engine/Shaders/Private/VirtualShadowMaps/VirtualShadowMapSMRTTemplate.ush
andrew lauritzen bf84b62791 Improve texel dither to be more continuous and avoid artifacts at the edges of pages (which are now dynamically picked)
Add a world dither. Not necessarily useful but can be somewhat analygous to PCF radius.
Add permutation to SMRT samples = 0 (and possibly more in the future).

#preflight 628eab6fc826bd5a7f1135ec
#rb ola.olsson

#ROBOMERGE-AUTHOR: andrew.lauritzen
#ROBOMERGE-SOURCE: CL 20372897 via CL 20372913 via CL 20372922
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v949-20362246)

[CL 20373677 by andrew lauritzen in ue5-main branch]
2022-05-25 19:50:23 -04:00

130 lines
4.6 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
VirtualShadowMapSMRTTemplate.ush:
Required parameters before including this file:
1) Include "SMRTCommon.ush"
2) Define a "ray state" structure (FRayState here, but must be unique)
3) Implement FSMRTSample SMRTFindSample(inout FRayState RayState, float SampleTime)
4) Implement SMRTComputeOccluderDistance(FRayState RayState, float SampleDepth)
5) Include this file:
#define SMRT_TEMPLATE_RAY_STRUCT FRayState
#include "VirtualShadowMapSMRTTemplate.ush"
#undef SMRT_TEMPLATE_RAY_STRUCT
=============================================================================*/
// NOTE: No pragma(once) or inclusion guards because this file is meant to be
// included multiple times as our hacky way to generate template-like instantiations
// before HLSL supports templates natively.
// If defined, unrolls the loop and ignores the NumSteps parameter in favor of the define
#ifndef SMRT_TEMPLATE_STATIC_SAMPLES_PER_RAY
#define SMRT_TEMPLATE_STATIC_SAMPLES_PER_RAY -1
#endif
FSMRTResult SMRTRayCast(
inout SMRT_TEMPLATE_RAY_STRUCT RayState,
int NumSteps,
float StepOffset)
{
float DepthHistory = -1;
float DepthHistoryTime = -1;
float DepthSlope = 0;
int SampleMissCount = 0;
float OccluderDistance = 100000;
const float TimeScale = -1.0f / NumSteps;
const float TimeBias = 1.0f + ( 1.0 - StepOffset ) * TimeScale;
// Backward delta. Time[i] - Time[i-1]
const float DeltaTimeScale = 2.0 * Pow2( TimeScale );
const float DeltaTimeBias = 2.0 * TimeScale * ( TimeBias - 0.5 * TimeScale );
bool bValidHit = false;
#if SMRT_TEMPLATE_STATIC_SAMPLES_PER_RAY >= 0
NumSteps = SMRT_TEMPLATE_STATIC_SAMPLES_PER_RAY;
[unroll]
#endif
for (int i = 0; i <= NumSteps; i++)
{
const float SampleTime = i == NumSteps ? 0 : Pow2( TimeScale * i + TimeBias );
const float DeltaTime = i == NumSteps ? Pow2( TimeScale * StepOffset ) : DeltaTimeScale * i + DeltaTimeBias;
FSMRTSample Sample = SMRTFindSample(RayState, SampleTime);
if (Sample.bValid)
{
const float SampleDepth = Sample.SampleDepth;
const float ReferenceDepth = Sample.ReferenceDepth;
if (DepthHistory < 0)
{
// First valid sample we've seen. Do a regular depth compare.
DepthHistory = SampleDepth;
DepthHistoryTime = SampleTime;
if (SampleDepth > ReferenceDepth)
{
OccluderDistance = SMRTComputeOccluderDistance(RayState, SampleDepth);
bValidHit = true;
break;
}
}
else
{
// Add a small relative error to the comparison to avoid missing surfaces due to numeric precision issues
// Without this there are occasionally flickering fireflies in fully shadowed regions with SMRT
const float EpsScale = 1.5f;
const float CompareTolerance = abs(Sample.CompareToleranceScale * DeltaTime) * EpsScale;
const bool bBehind = (SampleDepth - ReferenceDepth) > CompareTolerance;
float DeltaHistoryTime = SampleTime - DepthHistoryTime;
float DepthForComparison = SampleDepth;
if (bBehind)
{
#if SMRT_EXTRAPOLATE_WITH_SLOPE
DepthForComparison = DepthSlope * DeltaHistoryTime + DepthHistory;
#else
DepthForComparison = DepthHistory;
#endif
}
else
{
// This must be the second valid sample we've seen, as the first will take the DepthHistory < 0 path
// Only update the slope if we sampled a new texel; otherwise it will just zero out the slope
// This can happen at high sample counts with rays that are nearly parallel to the light direction
if (SampleDepth != DepthHistory) // Exact test is fine here; point sampled texel with be identical
{
// NOTE: DCE will remove all this if SMRT_EXTRAPOLATE_WITH_SLOPE is false
const float SlopeClamp = 1e-5f;
DepthSlope = (SampleDepth - DepthHistory) / DeltaHistoryTime;
DepthSlope = clamp(DepthSlope, -SlopeClamp, SlopeClamp);
}
DepthHistory = SampleDepth;
DepthHistoryTime = SampleTime;
}
float DepthDiff = ReferenceDepth - DepthForComparison;
float HalfCompareTolerance = 0.5 * CompareTolerance;
bool bHit = abs(DepthDiff + HalfCompareTolerance) < HalfCompareTolerance;
if (bHit)
{
OccluderDistance = SMRTComputeOccluderDistance(RayState, SampleDepth);
bValidHit = true;
break;
}
}
}
else
{
++SampleMissCount;
}
}
FSMRTResult Result;
Result.bValidHit = bValidHit;
Result.OccluderDistance = OccluderDistance;
Result.SampleMissCount = SampleMissCount;
return Result;
}