// 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 HitGroupData; StructuredBuffer RayTracingSceneMetadata; RWStructuredBuffer RWInstanceHitCountBuffer; #endif RWTexture2D RWLightSamples; RWTexture2D RWLightSampleRays; Buffer CompactedTraceTexelData; Buffer CompactedTraceTexelAllocator; Texture2D DownsampledSceneDepth; Texture2D 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 } }