Files
UnrealEngine/Engine/Shaders/Private/Lumen/LumenScreenProbeTracingCommon.ush
2025-05-18 13:04:45 +08:00

174 lines
6.0 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "../MonteCarlo.ush"
#include "../BlueNoise.ush"
float2 GetProbeTexelCenter(uint2 ScreenTileCoord)
{
#define JITTER_RAY_DIRECTION 1
#if JITTER_RAY_DIRECTION
#define BLUE_NOISE_LUT 1
#if BLUE_NOISE_LUT
return BlueNoiseVec2(ScreenTileCoord, ScreenProbeRayDirectionFrameIndex);
#else
uint2 RandomSeed = Rand3DPCG16(int3(ScreenTileCoord, 0)).xy;
return Hammersley16(ScreenProbeRayDirectionFrameIndex % 8, 8, RandomSeed);
#endif
#else
return float2(0.5, 0.5);
#endif
}
RWTexture2D<uint> RWTraceHit;
RWTexture2D<float3> RWTraceRadiance;
Texture2D<uint> TraceHit;
bool IsTraceMoving(float3 ProbeWorldPosition, float ProbeSceneDepth, uint2 ScreenProbeAtlasCoord, float3 HitWorldPosition, float3 HitWorldVelocity)
{
//@todo - for pixels that use the velocity texture in GetHistoryScreenPosition, velocities transformed to world space are too inaccurate to use for a dis-occlusion test
// See DEBUG_VISUALIZE_PROBE_WORLD_SPEED
#define VELOCITY_IS_ACCURATE 0
#if VELOCITY_IS_ACCURATE
float3 ProbeWorldVelocity = ScreenProbeWorldVelocity.Load(int3(ScreenProbeAtlasCoord, 0)).xyz;
float VelocityDampening = lerp(1, .1f, saturate(ProbeSceneDepth / 10000.0f));
float3 ProbeToHit = HitWorldPosition - ProbeWorldPosition;
float3 PrevProbeToPrevHit = HitWorldPosition - HitWorldVelocity * VelocityDampening - (ProbeWorldPosition - ProbeWorldVelocity * VelocityDampening);
float3 CosAngle = dot(ProbeToHit, PrevProbeToPrevHit) / max(length(ProbeToHit) * length(PrevProbeToPrevHit), .0001f);
float CosProbeTraceVelocityAngleThreshold = cos(1.0f * (float)PI / 180.0f);
return CosAngle < CosProbeTraceVelocityAngleThreshold;
#else
float ProbeWorldSpeed = GetScreenProbeSpeed(ScreenProbeAtlasCoord);
return abs(ProbeWorldSpeed - length(HitWorldVelocity)) / max(ProbeSceneDepth, 100.0f) > RelativeSpeedDifferenceToConsiderLightingMoving;
#endif
}
float EncodeProbeHitDistanceForFiltering(float HitDistance)
{
// Encode one negative value to indicate invalid ray
return sqrt(HitDistance / GetProbeMaxHitDistance()) * 254.0f / 255.0f + 1.0f / 255.0f;
}
float DecodeProbeHitDistanceForFiltering(float Encoded)
{
float Linear = Encoded * Encoded * GetProbeMaxHitDistance();
return (Linear - 1.0f / 255.0f) * 255.0f / 254.0f;
}
// Stores a packed ray info for each tracing shader lane storing the direction and mip level of the ray to trace
Texture2D<uint> StructuredImportanceSampledRayInfosForTracing;
uint MaxImportanceSamplingOctahedronResolution;
uint ScreenProbeBRDFOctahedronResolution;
#define INVALID_TRACING_COORD 0xFE
uint PackRayInfo(uint2 TexelCoord, uint Level)
{
// Pack in 16 bits
return (TexelCoord.x & 0x3F) | ((TexelCoord.y & 0x3F) << 6) | ((Level & 0xF) << 12);
}
void UnpackRayInfo(uint RayInfo, out uint2 TexelCoord, out uint Level)
{
TexelCoord.x = RayInfo & 0x3F;
TexelCoord.y = (RayInfo >> 6) & 0x3F;
Level = (RayInfo >> 12) & 0xF;
}
void GetProbeTracingUV(
uint2 TraceBufferCoord,
uint2 TracingTexelCoord,
float2 ProbeTexelCenter,
float NumSupersamples,
out float2 ProbeUV,
out float ConeHalfAngle)
{
#if STRUCTURED_IMPORTANCE_SAMPLING
uint RayInfo = StructuredImportanceSampledRayInfosForTracing[TraceBufferCoord];
uint2 RayTexelCoord;
uint RayLevel;
UnpackRayInfo(RayInfo, RayTexelCoord, RayLevel);
uint MipSize = MaxImportanceSamplingOctahedronResolution >> RayLevel;
float InvSupersampledMipSize = 1.0f / (MipSize * NumSupersamples);
ProbeUV = (RayTexelCoord * NumSupersamples + ProbeTexelCenter) * InvSupersampledMipSize;
ConeHalfAngle = acosFast(1.0f - 1.0f * InvSupersampledMipSize * InvSupersampledMipSize);
#else
ProbeUV = (TracingTexelCoord * NumSupersamples + ProbeTexelCenter) / float(ScreenProbeTracingOctahedronResolution * NumSupersamples);
// Evenly distributing the sphere solid angle among all cones
ConeHalfAngle = acosFast(1.0f - 1.0f / (float)(ScreenProbeTracingOctahedronResolution * ScreenProbeTracingOctahedronResolution * NumSupersamples * NumSupersamples));
#endif
}
uint2 GetTraceBufferCoord(uint2 ScreenProbeAtlasCoord, uint2 TraceTexelCoord)
{
#define DEINTERLEAVED_TRACE_BUFFER_STORAGE 0
#if DEINTERLEAVED_TRACE_BUFFER_STORAGE
return TraceTexelCoord * ScreenProbeAtlasViewSize + ScreenProbeAtlasCoord;
#else
return ScreenProbeAtlasCoord * ScreenProbeTracingOctahedronResolution + TraceTexelCoord;
#endif
}
bool ShouldTraceScreenProbeTexel(uint2 TraceBufferCoord, float ProbeSceneDepth)
{
bool bShouldTrace = ProbeSceneDepth > 0.0f;
return bShouldTrace;
}
void GetScreenProbeTexelRay(
uint2 TraceBufferCoord,
uint2 TraceTexelCoord,
uint2 ScreenTileCoord,
float3 TranslatedWorldPosition,
inout float3 RayDirection,
inout float TraceDistance,
inout float ConeHalfAngle)
{
float2 ProbeUV;
GetProbeTracingUV(TraceBufferCoord, TraceTexelCoord, GetProbeTexelCenter(ScreenTileCoord), 1, ProbeUV, ConeHalfAngle);
RayDirection = EquiAreaSphericalMapping(ProbeUV);
}
float3 GetScreenProbeNormalForBiasing(uint2 ScreenProbeAtlasCoord, float3 RayWorldDirection, out bool bBackfaceRay)
{
bBackfaceRay = false;
float3 SceneNormal = GetScreenProbeNormal(ScreenProbeAtlasCoord);
if (GetScreenProbeIsTwoSidedFoliage(ScreenProbeAtlasCoord))
{
bBackfaceRay = dot(SceneNormal, RayWorldDirection) < 0.0f;
if (bBackfaceRay)
{
SceneNormal *= -1;
}
}
return SceneNormal;
}
float3 GetScreenProbeNormalForBiasing(uint2 ScreenProbeAtlasCoord, float3 RayWorldDirection)
{
bool bBackfaceRay;
return GetScreenProbeNormalForBiasing(ScreenProbeAtlasCoord, RayWorldDirection, bBackfaceRay);
}
void WriteTraceHit(uint2 TraceBufferCoord, float HitDistance, bool bHit, bool bFastMoving, bool bReachedRadianceCache)
{
RWTraceHit[TraceBufferCoord] = EncodeProbeRayDistance(HitDistance, bHit, bFastMoving, bReachedRadianceCache);
}
FProbeRayDistance ReadTraceHit(uint2 TraceBufferCoord)
{
return DecodeProbeRayDistance(TraceHit[TraceBufferCoord].x);
}
void ReadTraceTexel(uint DispatchThreadId, out uint ScreenProbeIndex, out uint2 TraceTexelCoord)
{
DecodeScreenProbeTraceTexel(CompactedTraceTexelData[DispatchThreadId], ScreenProbeIndex, TraceTexelCoord);
}