138 lines
4.4 KiB
HLSL
138 lines
4.4 KiB
HLSL
// 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)
|
|
- NOTE: ReferenceDepth must always be set, even if the sample is invalid
|
|
4) 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)
|
|
{
|
|
// NOTE: Need a magic initializer that we can detect. Would be natural to use DepthHistoryTime for this,
|
|
// but we want that register to disappear (DCE) when SMRT_EXTRAPOLATE_SLOPE is disabled.
|
|
// DepthHistory *can* be negative though when crossing clipmap boundaries, as the depth range expands.
|
|
// In practice it will only ever be down to -2 or so.
|
|
const float DepthHistoryNotSet = -10000.0f;
|
|
float DepthHistory = DepthHistoryNotSet;
|
|
|
|
float DepthHistoryTime = -1.0f;
|
|
float DepthSlope = 0;
|
|
|
|
const float TimeScale = -1.0f / NumSteps;
|
|
const float TimeBias = 1.0f + ( 1.0 - StepOffset ) * TimeScale;
|
|
|
|
// This doesn't get used in the first iteration of the loop and so will always
|
|
// be valid by the time that it does.
|
|
float PrevReferenceDepth = -1;
|
|
|
|
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 );
|
|
|
|
FSMRTSample Sample = SMRTFindSample(RayState, SampleTime);
|
|
const float ReferenceDepth = Sample.ReferenceDepth;
|
|
|
|
if (Sample.bResetExtrapolation)
|
|
{
|
|
DepthSlope = Sample.ExtrapolateSlope;
|
|
}
|
|
|
|
if (Sample.bValid)
|
|
{
|
|
const float SampleDepth = Sample.SampleDepth;
|
|
if (DepthHistory == DepthHistoryNotSet)
|
|
{
|
|
// First valid sample we've seen. Do a regular depth compare.
|
|
DepthHistory = SampleDepth;
|
|
DepthHistoryTime = SampleTime;
|
|
if (SampleDepth > ReferenceDepth)
|
|
{
|
|
FSMRTResult Result;
|
|
Result.bValidHit = true;
|
|
Result.HitDepth = SampleDepth;
|
|
return Result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const float DeltaReferenceDepth = ReferenceDepth - PrevReferenceDepth;
|
|
|
|
// 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.05f;
|
|
const float CompareTolerance = abs(DeltaReferenceDepth) * EpsScale;
|
|
|
|
const bool bBehind = (SampleDepth - ReferenceDepth) > CompareTolerance;
|
|
float DepthForComparison = SampleDepth;
|
|
|
|
float DeltaHistoryTime = SampleTime - DepthHistoryTime;
|
|
|
|
if (bBehind)
|
|
{
|
|
#if SMRT_EXTRAPOLATE_SLOPE
|
|
DepthForComparison = DepthSlope * DeltaHistoryTime + DepthHistory;
|
|
#else
|
|
DepthForComparison = DepthHistory;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (SampleDepth != DepthHistory)
|
|
{
|
|
// NOTE: DCE will remove this if SMRT_EXTRAPOLATE_WITH_SLOPE is false
|
|
const float SlopeClamp = Sample.ExtrapolateSlope;
|
|
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)
|
|
{
|
|
FSMRTResult Result;
|
|
Result.bValidHit = true;
|
|
Result.HitDepth = DepthForComparison;
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
PrevReferenceDepth = ReferenceDepth;
|
|
}
|
|
}
|
|
|
|
FSMRTResult Result;
|
|
Result.bValidHit = false;
|
|
Result.HitDepth = -1.0f;
|
|
return Result;
|
|
}
|