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

230 lines
8.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Shared/RayTracingTypes.h"
#include "../Common.ush"
#include "../MonteCarlo.ush"
#include "../SceneTextureParameters.ush"
#include "LumenCardCommon.ush"
#include "LumenTracingCommon.ush"
#define RADIANCE_CACHE_DEPTH_TEST_SPHERE_PARALLAX 1
#include "LumenRadianceCacheCommon.ush"
#include "LumenScreenProbeCommon.ush"
#include "LumenScreenProbeTracingCommon.ush"
#include "LumenFloatQuantization.ush"
#ifndef THREADGROUP_SIZE_2D
#define THREADGROUP_SIZE_2D 8
#endif
#ifndef THREADGROUP_SIZE_1D
#define THREADGROUP_SIZE_1D THREADGROUP_SIZE_2D * THREADGROUP_SIZE_2D
#endif
#define RAY_TRACING_PASS_DEFAULT 0
#define RAY_TRACING_PASS_FAR_FIELD 1
#define RAY_TRACING_PASS_HIT_LIGHTING 2
RWBuffer<uint> RWHardwareRayTracingIndirectArgs;
uint2 OutputThreadGroupSize;
#ifdef FLumenScreenProbeHardwareRayTracingIndirectArgsCS
[numthreads(1, 1, 1)]
void FLumenScreenProbeHardwareRayTracingIndirectArgsCS()
{
WriteDispatchIndirectArgs(RWHardwareRayTracingIndirectArgs, 0, (CompactedTraceTexelAllocator[0] + OutputThreadGroupSize.x - 1) / OutputThreadGroupSize.x, 1, 1);
}
#endif
#if LUMEN_HARDWARE_RAYTRACING || LUMEN_HARDWARE_INLINE_RAYTRACING
#include "LumenHardwareRayTracingCommon.ush"
RaytracingAccelerationStructure TLAS;
RaytracingAccelerationStructure FarFieldTLAS;
#if LUMEN_HARDWARE_INLINE_RAYTRACING
StructuredBuffer<FHitGroupRootConstants> HitGroupData;
StructuredBuffer<FRayTracingSceneMetadataRecord> RayTracingSceneMetadata;
RWStructuredBuffer<uint> RWInstanceHitCountBuffer;
#endif // LUMEN_HARDWARE_INLINE_RAYTRACING
uint HitLightingForceOpaque;
uint HitLightingShadowMode;
uint HitLightingShadowTranslucencyMode;
uint HitLightingDirectLighting;
uint HitLightingSkylight;
float MaxTraceDistance;
float NearFieldSceneRadius;
float NearFieldMaxTraceDistance;
float FarFieldBias;
float FarFieldMaxTraceDistance;
float PullbackBias;
float NormalBias;
float BiasForTracesFromHairPixels;
float AvoidSelfIntersectionTraceDistance;
float SkipFirstTwoSidedHitDistance;
float MinTraceDistanceToSampleSurfaceCache;
uint MaxTraversalIterations;
uint MeshSectionVisibilityTest;
LUMEN_HARDWARE_RAY_TRACING_ENTRY(LumenScreenProbeGatherHardwareRayTracing)
{
uint ThreadIndex = DispatchThreadIndex.x;
uint GroupIndex = DispatchThreadIndex.y;
uint CompactedTraceIndex = GroupIndex * THREADGROUP_SIZE_1D + ThreadIndex;
if (CompactedTraceIndex < CompactedTraceTexelAllocator[0])
{
uint ScreenProbeIndex;
uint2 TraceTexelCoord;
DecodeScreenProbeTraceTexel(CompactedTraceTexelData[CompactedTraceIndex], ScreenProbeIndex, TraceTexelCoord);
uint2 ScreenProbeScreenPosition = GetScreenProbeScreenPosition(ScreenProbeIndex);
uint2 ScreenTileCoord = GetScreenTileCoord(ScreenProbeScreenPosition);
uint LinearCoord = ScreenTileCoord.y * ScreenProbeViewSize.x + ScreenTileCoord.x;
float2 ScreenUV = GetScreenUVFromScreenProbePosition(ScreenProbeScreenPosition);
uint2 ScreenProbeAtlasCoord = uint2(ScreenProbeIndex % ScreenProbeAtlasViewSize.x, ScreenProbeIndex / ScreenProbeAtlasViewSize.x);
uint2 ScreenProbeTraceCoord = GetTraceBufferCoord(ScreenProbeAtlasCoord, TraceTexelCoord);
float TraceHitDistance = DecodeProbeRayDistance(RWTraceHit[ScreenProbeTraceCoord]).HitDistance;
float SceneDepth = GetScreenProbeDepth(ScreenProbeAtlasCoord);
float3 TranslatedWorldPosition = GetTranslatedWorldPositionFromScreenUV(ScreenUV, SceneDepth);
float2 ProbeTexelCenter = GetProbeTexelCenter(ScreenTileCoord);
const float Noise = ProbeTexelCenter.y;
float2 ProbeUV;
float ConeHalfAngle;
GetProbeTracingUV(ScreenProbeTraceCoord, TraceTexelCoord, ProbeTexelCenter, 1, ProbeUV, ConeHalfAngle);
float RayBias = 0.0f;
if (GetScreenProbeIsHair(ScreenProbeAtlasCoord))
{
RayBias = BiasForTracesFromHairPixels;
}
#if ENABLE_FAR_FIELD_TRACING
{
RayBias = max(RayBias, FarFieldBias);
}
#endif
float3 RayDirection = EquiAreaSphericalMapping(ProbeUV);
float ClippedNearFieldMaxTraceDistance = ClipAndDitherNearFieldMaxTraceDistance(
TranslatedWorldPosition,
RayDirection,
ScreenTileCoord,
NearFieldSceneRadius,
NearFieldMaxTraceDistance,
/*NearFieldMaxTraceDistanceDitherScale*/ 0.0f);
float TraceMaxDistance = ClippedNearFieldMaxTraceDistance;
bool bReachedRadianceCache = false;
#if DIM_RADIANCE_CACHE
{
float3 RayOriginWorldPos = TranslatedWorldPosition - DFHackToFloat(PrimaryView.PreViewTranslation);
FRadianceCacheCoverage Coverage = GetRadianceCacheCoverage(RayOriginWorldPos, RayDirection, 0); // LUMEN_LWC_TODO
if (Coverage.bValid)
{
TraceMaxDistance = min(TraceMaxDistance, Coverage.MinTraceDistanceBeforeInterpolation);
bReachedRadianceCache = true;
}
}
#endif
#if RAY_TRACING_PASS == RAY_TRACING_PASS_FAR_FIELD
{
TraceMaxDistance = max(TraceMaxDistance, FarFieldMaxTraceDistance);
}
#endif
FRayDesc Ray;
Ray.Origin = TranslatedWorldPosition;
Ray.Direction = RayDirection;
Ray.TMin = max(TraceHitDistance, RayBias);
Ray.TMax = max(TraceMaxDistance, RayBias);
// Apply PullbackBias only if ray didn't reach the end, so that we don't retrace it again
if (Ray.TMin < Ray.TMax)
{
Ray.TMin = max(Ray.TMin - PullbackBias, RayBias);
}
float3 ProbeWorldNormalForBiasing = GetScreenProbeNormalForBiasing(ScreenProbeAtlasCoord, Ray.Direction);
Ray.Origin += NormalBias * ProbeWorldNormalForBiasing;
FRayCone RayCone = (FRayCone)0;
RayCone = PropagateRayCone(RayCone, ConeHalfAngle, 0.0);
FRayTracedLightingContext Context = CreateRayTracedLightingContext(
RayCone,
ScreenTileCoord,
ScreenTileCoord.y * ScreenProbeViewSize.x + ScreenTileCoord.x,
/*CullingMode*/ RAY_FLAG_CULL_BACK_FACING_TRIANGLES,
MaxTraversalIterations,
MeshSectionVisibilityTest != 0);
Context.MinTraceDistanceToSampleSurfaceCache = MinTraceDistanceToSampleSurfaceCache;
#if LUMEN_HARDWARE_INLINE_RAYTRACING
{
Context.HitGroupData = HitGroupData;
Context.RayTracingSceneMetadata = RayTracingSceneMetadata;
Context.RWInstanceHitCountBuffer = RWInstanceHitCountBuffer;
}
#endif
FRayTracedLightingResult Result = CreateRayTracedLightingResult(Ray);
if (Ray.TMin < Ray.TMax)
{
#if RAY_TRACING_PASS == RAY_TRACING_PASS_HIT_LIGHTING
{
Context.bHitLightingDirectLighting = HitLightingDirectLighting != 0;
Context.bHitLightingSkylight = HitLightingSkylight != 0;
Context.bUseReflectionCaptures = false;
Context.bForceOpaque = HitLightingForceOpaque;
Context.HitLightingShadowMode = HitLightingShadowMode;
Context.HitLightingShadowTranslucencyMode = HitLightingShadowTranslucencyMode;
Context.HitLightingShadowMaxTraceDistance = NearFieldMaxTraceDistance;
Result = TraceAndCalculateRayTracedLighting(TLAS, FarFieldTLAS, Ray, Context);
}
#elif RAY_TRACING_PASS == RAY_TRACING_PASS_DEFAULT
{
Result = TraceSurfaceCacheRay(TLAS, Ray, Context);
}
#elif RAY_TRACING_PASS == RAY_TRACING_PASS_FAR_FIELD
{
Result = TraceSurfaceCacheFarFieldRay(FarFieldTLAS, Ray, Context);
}
#endif
}
bool bMoving = false;
if (Result.bIsHit)
{
float3 HitTranslatedWorldPosition = Ray.Origin + Ray.Direction * Result.TraceHitDistance;
float3 HitWorldVelocity = HitTranslatedWorldPosition - CalcPrevTranslatedWorldPositionFromGPUSceneInstanceIndex(HitTranslatedWorldPosition, Result.SceneInstanceIndex);
bMoving = IsTraceMoving(TranslatedWorldPosition, SceneDepth, ScreenProbeAtlasCoord, HitTranslatedWorldPosition, HitWorldVelocity);
}
Result.Radiance += GetSkylightLeaking(Ray.Direction, Result.TraceHitDistance);
Result.Radiance *= View.PreExposure;
if (SampleHeightFog > 0)
{
float3 OriginToCollider = Ray.Direction * Result.TraceHitDistance;
float CoverageForFog = 1.0; // There is always something or the sky fallback.
Result.Radiance.rgb = GetFogOnLuminance(Result.Radiance.rgb, CoverageForFog, Ray.Origin, Ray.Direction, Result.TraceHitDistance);
}
RWTraceRadiance[ScreenProbeTraceCoord] = QuantizeForFloatRenderTarget(Result.Radiance, Noise);
RWTraceHit[ScreenProbeTraceCoord] = EncodeProbeRayDistance(min(Result.TraceHitDistance, MaxTraceDistance), Result.bIsHit, bMoving, bReachedRadianceCache);
}
}
#endif // LUMEN_HARDWARE_RAYTRACING || LUMEN_HARDWARE_INLINE_RAYTRACING