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

254 lines
9.2 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Shared/RayTracingTypes.h"
#include "../Common.ush"
#include "../BlueNoise.ush"
#include "../IntersectionUtils.ush"
#include "../RayTracing/RayTracingCommon.ush"
#include "../SceneTexturesCommon.ush"
#include "MegaLights.ush"
#include "MegaLightsRayTracing.ush"
#include "../Lumen/LumenHardwareRayTracingPayloadCommon.ush"
#include "../Lumen/LumenHardwareRayTracingCommon.ush"
#if HAIR_VOXEL_TRACES
#include "../HairStrands/HairStrandsRaytracing.ush"
#endif
float RayTracingBias;
float RayTracingEndBias;
float RayTracingNormalBias;
float RayTracingPullbackBias;
uint DebugMode;
uint MaxTraversalIterations;
uint MeshSectionVisibilityTest;
RaytracingAccelerationStructure TLAS;
RaytracingAccelerationStructure FarFieldTLAS;
float NearFieldSceneRadius;
float NearFieldMaxTraceDistance;
float NearFieldMaxTraceDistanceDitherScale;
float FarFieldBias;
float FarFieldMaxTraceDistance;
#if LUMEN_HARDWARE_INLINE_RAYTRACING
StructuredBuffer<FHitGroupRootConstants> HitGroupData;
StructuredBuffer<FRayTracingSceneMetadataRecord> RayTracingSceneMetadata;
RWStructuredBuffer<uint> RWInstanceHitCountBuffer;
#endif
RWTexture2D<uint> RWLightSamples;
RWTexture2D<uint> RWLightSampleRays;
Buffer<uint> CompactedTraceTexelData;
Buffer<uint> CompactedTraceTexelAllocator;
Texture2D<float> DownsampledSceneDepth;
Texture2D<UNORM float3> DownsampledSceneWorldNormal;
RAY_TRACING_ENTRY_RAYGEN_OR_INLINE(HardwareRayTraceLightSamples)
{
uint ThreadIndex = DispatchThreadIndex.x;
uint GroupIndex = DispatchThreadIndex.y;
uint TraceTexelIndex = GroupIndex * 64 + ThreadIndex;
if (TraceTexelIndex < CompactedTraceTexelAllocator[0])
{
uint2 SampleCoord = UnpackTraceTexel(CompactedTraceTexelData[TraceTexelIndex]);
uint2 ScreenCoord = SampleCoordToScreenCoord(SampleCoord);
uint2 DownsampledScreenCoord = SampleCoordToDownsampledScreenCoord(SampleCoord);
FShaderPrintContext DebugContext = InitDebugContext(DownsampledScreenCoord, /*bDownsampled*/ true, float2(0.55, 0.45));
float2 ScreenUV = (ScreenCoord + 0.5f) * View.BufferSizeAndInvSize.zw;
float SceneDepth = DownsampledSceneDepth[DownsampledScreenCoord];
float3 SceneWorldNormal = normalize(DecodeNormal(DownsampledSceneWorldNormal[DownsampledScreenCoord]));
float3 TranslatedWorldPosition = GetTranslatedWorldPositionFromScreenUV(ScreenUV, SceneDepth);
FLightSample LightSample = UnpackLightSample(RWLightSamples[SampleCoord]);
FLightSampleRay LightSampleRay = UnpackLightSampleRay(RWLightSampleRays[SampleCoord]);
FLightSampleTrace LightSampleTrace = GetLightSampleTrace(TranslatedWorldPosition, LightSample.LocalLightIndex, LightSampleRay.UV);
const float ClippedNearFieldMaxTraceDistance = ClipAndDitherNearFieldMaxTraceDistance(
TranslatedWorldPosition,
LightSampleTrace.Direction,
ScreenCoord,
NearFieldSceneRadius,
NearFieldMaxTraceDistance,
NearFieldMaxTraceDistanceDitherScale);
const float MaxTraceDistance = LightSampleTrace.Distance - RayTracingEndBias;
FRayDesc Ray = (FRayDesc)0;
Ray.Origin = TranslatedWorldPosition;
Ray.Direction = LightSampleTrace.Direction;
Ray.TMin = max(LightSampleRay.RayDistance - RayTracingPullbackBias, RayTracingBias);
Ray.TMax = max(Ray.TMin, min(MaxTraceDistance, ClippedNearFieldMaxTraceDistance));
bool bFlipNormalBiasDirection = false;
if (LightSampleRay.bBackfaceDiffuse && dot(LightSampleTrace.Direction, SceneWorldNormal) < 0.0f)
{
bFlipNormalBiasDirection = true;
}
ApplyPositionBias(Ray.Origin, Ray.Direction, bFlipNormalBiasDirection ? -SceneWorldNormal : SceneWorldNormal, RayTracingNormalBias);
FRayCone RayCone = (FRayCone)0;
FRayTracedLightingContext LightingContext = CreateRayTracedLightingContext(
RayCone,
0,
0, // dummy coordinate
/*CullingMode*/ RAY_FLAG_CULL_FRONT_FACING_TRIANGLES,
MaxTraversalIterations,
MeshSectionVisibilityTest != 0 || MEGA_LIGHTS_LIGHTING_CHANNELS);
const FForwardLightData ForwardLightData = GetForwardLightData(LightSample.LocalLightIndex, 0);
LightingContext.LightingChannelMask = UnpackLightingChannelMask(ForwardLightData);
// Shadows don't need closest hit distance
LightingContext.bAcceptFirstHitAndEndSearch = true;
#if LUMEN_HARDWARE_INLINE_RAYTRACING
LightingContext.HitGroupData = HitGroupData;
LightingContext.RayTracingSceneMetadata = RayTracingSceneMetadata;
LightingContext.RWInstanceHitCountBuffer = RWInstanceHitCountBuffer;
#endif // LUMEN_HARDWARE_INLINE_RAYTRACING
LightingContext.InstanceMask = RAY_TRACING_MASK_OPAQUE_SHADOW;
LightingContext.bIsShadowRay = true;
// by default bIsShadowRay causes RAY_FLAG_SKIP_CLOSEST_HIT_SHADER to be used, but for visualizations we need CHS to run to get hit data such as HitT
if (DebugContext.bIsActive && DebugMode == DEBUG_MODE_VISUALIZE_TRACING)
{
LightingContext.bForceClosestHitShader = true;
}
#if SUPPORT_CONTINUATION
// Need to evaluate CHS as this pass depends on TraceResult.bAlphaMasked
LightingContext.bForceClosestHitShader = true;
#endif
#if MEGA_LIGHTS_EVALUATE_MATERIALS
FLumenMinimalRayResult TraceResult = (FLumenMinimalRayResult)0;
{
FPackedMaterialClosestHitPayload Payload = (FPackedMaterialClosestHitPayload)0;
Payload.SetLumenPayload();
Payload.SetIgnoreTranslucentMaterials();
Payload.SetMinimalPayloadMode();
Payload.SetRandom(0.5f); // Is an actual random number needed?
uint RayFlags = RAY_FLAG_SKIP_CLOSEST_HIT_SHADER;
RayFlags |= LightingContext.CullingMode;
RayFlags |= LightingContext.bAcceptFirstHitAndEndSearch ? RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH : 0;
TraceLumenShadingRay(TLAS, RayFlags, LightingContext.InstanceMask, RAY_TRACING_SHADER_SLOT_SHADOW, RAY_TRACING_NUM_SHADER_SLOTS, 0, Ray.GetNativeDesc(), Payload);
TraceResult.bHit = Payload.IsHit();
if (TraceResult.bHit)
{
TraceResult.HitT = Payload.HitT;
}
#if ENABLE_FAR_FIELD_TRACING
else if(Ray.TMax < MaxTraceDistance)
{
FRayDesc FarFieldRay = Ray;
FarFieldRay.TMin = max(Ray.TMax, FarFieldBias);
FarFieldRay.TMax = max(FarFieldRay.TMin, min(MaxTraceDistance, FarFieldMaxTraceDistance));
LightingContext.bIsFarFieldRay = true;
FPackedMaterialClosestHitPayload FarFieldPayload = (FPackedMaterialClosestHitPayload)0;
FarFieldPayload.SetLumenPayload();
FarFieldPayload.SetIgnoreTranslucentMaterials();
FarFieldPayload.SetMinimalPayloadMode();
FarFieldPayload.SetRandom(0.5f); // Is an actual random number needed?
TraceLumenShadingRay(FarFieldTLAS, RayFlags, LightingContext.InstanceMask, RAY_TRACING_SHADER_SLOT_SHADOW, RAY_TRACING_NUM_SHADER_SLOTS, 0, FarFieldRay.GetNativeDesc(), FarFieldPayload);
TraceResult.bHit = FarFieldPayload.IsHit();
if (TraceResult.bHit)
{
TraceResult.HitT = FarFieldPayload.HitT;
}
}
#endif
}
#else
FLumenMinimalRayResult TraceResult = TraceLumenMinimalRay(TLAS, Ray, LightingContext);
#if ENABLE_FAR_FIELD_TRACING
{
if (!TraceResult.bHit && Ray.TMax < MaxTraceDistance)
{
FRayDesc FarFieldRay = Ray;
FarFieldRay.TMin = max(Ray.TMax, FarFieldBias);
FarFieldRay.TMax = max(FarFieldRay.TMin, min(MaxTraceDistance, FarFieldMaxTraceDistance));
LightingContext.bIsFarFieldRay = true;
TraceResult = TraceLumenMinimalRay(FarFieldTLAS, FarFieldRay, LightingContext);
}
}
#endif
#endif
#if HAIR_VOXEL_TRACES
if (!TraceResult.bHit)
{
// #ml_todo: replace with spatiotemporal blue noise
RandomSequence RandSequence;
RandomSequence_Initialize(RandSequence, SampleCoord, 0, MegaLightsStateFrameIndex, 1);
const float HitT = TraverseHair(ScreenCoord, RandSequence, Ray.Origin, Ray.Direction, Ray.TMax, VirtualVoxel.Raytracing_ShadowOcclusionThreshold);
if (HitT > 0 && HitT < (TraceResult.bHit ? TraceResult.HitT : Ray.TMax))
{
TraceResult.HitT = HitT;
TraceResult.bHit = true;
}
}
#endif
if (DebugContext.bIsActive && DebugMode == DEBUG_MODE_VISUALIZE_TRACING)
{
const FForwardLightData ForwardLightData = GetForwardLightData(LightSample.LocalLightIndex, 0);
const FDeferredLightData LightData = ConvertToDeferredLight(ForwardLightData);
float3 RayStart = Ray.Origin + Ray.Direction * Ray.TMin;
float3 RayEnd = Ray.Origin + Ray.Direction * (TraceResult.bHit ? TraceResult.HitT : Ray.TMax);
float4 RayColor = float4(LightData.Color.xyz / Luminance(LightData.Color.xyz), 1.0f);
#if MEGA_LIGHTS_EVALUATE_MATERIALS
RayColor = ColorRed;
#endif
if (TraceResult.bHit)
{
RayColor.xyz = 0.0f;
}
AddLineTWS(DebugContext, RayStart, RayEnd, RayColor);
AddCrossTWS(DebugContext, RayEnd, 2.0f, RayColor);
}
#if SUPPORT_CONTINUATION
if (TraceResult.bAlphaMasked)
{
// do nothing so sample gets retraced with material evaluation
// can't shorten the retrace ray since this trace was done with bAcceptFirstHitAndEndSearch
}
else
{
// Mark sample as complete to skip continuation
LightSampleRay.bCompleted = true;
RWLightSampleRays[SampleCoord] = PackLightSampleRay(LightSampleRay);
if (TraceResult.bHit)
{
LightSample.bVisible = false;
}
RWLightSamples[SampleCoord] = PackLightSample(LightSample);
}
#else
if (TraceResult.bHit) // if not using continuation, only need to write to RWLightSamples on hits
{
LightSample.bVisible = false;
RWLightSamples[SampleCoord] = PackLightSample(LightSample);
}
#endif
}
}