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

149 lines
5.2 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../Common.ush"
#include "../ShadingCommon.ush"
#include "../ColorMap.ush"
#include "../BlueNoise.ush"
#include "RayTracingCommon.ush"
#include "RayTracingDeferredMaterials.ush"
#include "RayTracingDeferredShadingCommon.ush"
#include "../Substrate/Substrate.ush"
#include "../Lumen/LumenPosition.ush"
#include "/Engine/Shared/RayTracingDebugDefinitions.h"
#include "TraceRayInline.ush"
RWTexture2D<float4> Output;
RaytracingAccelerationStructure TLAS;
uint VisualizationMode;
float TraversalBoxScale;
float TraversalClusterScale;
float TraversalTriangleScale;
float NormalBias;
float TraceDistance;
struct FNaniteTraceRayInlineCallback : FDefaultTraceRayInlineCallback
{
uint ClusterIntersectionCount;
bool OnProceduralPrimitive(float3 ObjectRayOrigin, float3 ObjectRayDirection, float RayTMin, inout float RayTCurrent, FTraceRayInlineProceduralIntersectionParameters ProceduralIntersectionParameters)
{
#if ENABLE_TRACE_RAY_INLINE_PROCEDURAL_PRIMITIVE
uint PrimitiveID = ProceduralIntersectionParameters.InstanceID;
FPrimitiveSceneData PrimitiveData = GetPrimitiveData(PrimitiveID);
uint PrimitiveInstanceIndex = 0; // TODO
uint InstanceId = PrimitiveData.InstanceSceneDataOffset + PrimitiveInstanceIndex;
FInstanceSceneData InstanceData = GetInstanceSceneData(InstanceId);
// TODO: implement support for intersection with procedural primitives
#endif
return false;
}
};
FRayDesc CreateSecondaryRay(uint2 PixelCoord, float2 ScreenUV, out bool bIsValid)
{
#if SUBTRATE_GBUFFER_FORMAT==1
const FSubstrateTopLayerData TopLayerData = SubstrateUnpackTopLayerData(Substrate.TopLayerTexture.Load(uint3(PixelCoord, 0)));
bIsValid = IsSubstrateMaterial(TopLayerData);
const float3 WorldNormal = TopLayerData.WorldNormal;
const float Depth = ConvertFromDeviceZ(SceneDepthTexture.Load(int3(PixelCoord, 0)).r);
#else
const FGBufferData GBufferData = GetGBufferDataFromSceneTexturesLoad(PixelCoord);
bIsValid = GBufferData.ShadingModelID != SHADINGMODELID_UNLIT;
const float3 WorldNormal = GBufferData.WorldNormal;
const float Depth = GBufferData.Depth;
#endif
FRayDesc Ray = (FRayDesc)0;
if (bIsValid)
{
float3 TranslatedWorldPosition = GetTranslatedWorldPositionFromScreenUV(ScreenUV, Depth);
float3x3 TangentBasis = GetTangentBasis(WorldNormal);
float2 UniformRandom = BlueNoiseVec2(PixelCoord, View.StateFrameIndex);
float4 HemisphereSample = CosineSampleHemisphere(UniformRandom);
float3 RayDirection = mul(HemisphereSample.xyz, TangentBasis);
Ray.Origin = TranslatedWorldPosition;
Ray.TMin = 0;
Ray.Direction = RayDirection;
Ray.TMax = TraceDistance;
ApplyCameraRelativeDepthBias(Ray, PixelCoord, ConvertToDeviceZ(Depth), WorldNormal, NormalBias);
}
return Ray;
}
[numthreads(INLINE_RAY_TRACING_THREAD_GROUP_SIZE_X, INLINE_RAY_TRACING_THREAD_GROUP_SIZE_Y, 1)]
void RayTracingDebugTraversalCS(uint3 DispatchThread : SV_DispatchThreadID)
{
uint2 PixelCoord = DispatchThread.xy + View.ViewRectMin.xy;
float2 RenderTargetUV = (float2(PixelCoord) + .5f) * View.BufferSizeAndInvSize.zw;
FRayDesc Ray = CreatePrimaryRay(RenderTargetUV);
bool bIsValid = true;
if (VisualizationMode == RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_ALL
|| VisualizationMode == RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_CLUSTER
|| VisualizationMode == RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_NODE
|| VisualizationMode == RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_TRIANGLE)
{
Ray = CreateSecondaryRay(PixelCoord, RenderTargetUV, bIsValid);
}
if (!bIsValid)
{
Output[PixelCoord] = 0.0f;
return;
}
uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES | RAY_FLAG_FORCE_OPAQUE;
FNaniteTraceRayInlineCallback NaniteCallback = (FNaniteTraceRayInlineCallback)0;
FTraceRayInlineContext TraceRayInlineContext = CreateTraceRayInlineContext();
TraceRayInlineContext.bProcedural = ENABLE_TRACE_RAY_INLINE_PROCEDURAL_PRIMITIVE;
FTraceRayInlineResult TraceResult = TraceRayInlineWithCallback(TLAS, RayFlags, RAY_TRACING_MASK_ALL, Ray.GetNativeDesc(), TraceRayInlineContext, NaniteCallback);
float4 Result = 0;
const uint Intersections = TraceResult.TraversalStatistics.NodeIntersectionCount + NaniteCallback.ClusterIntersectionCount + TraceResult.TraversalStatistics.TriangleIntersectionCount;
switch (VisualizationMode)
{
default:
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_PRIMARY_ALL:
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_ALL:
Result.rgb = ColorMapTurbo(Intersections / (TraversalBoxScale + TraversalTriangleScale));
break;
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_PRIMARY_CLUSTER:
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_CLUSTER:
Result.rgb = ColorMapTurbo(NaniteCallback.ClusterIntersectionCount / TraversalClusterScale);
break;
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_PRIMARY_NODE:
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_NODE:
Result.rgb = ColorMapTurbo(TraceResult.TraversalStatistics.NodeIntersectionCount / TraversalBoxScale);
break;
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_PRIMARY_TRIANGLE:
case RAY_TRACING_DEBUG_VIZ_TRAVERSAL_SECONDARY_TRIANGLE:
Result.rgb = ColorMapTurbo(TraceResult.TraversalStatistics.TriangleIntersectionCount / TraversalTriangleScale);
break;
}
#if PRINT_TRAVERSAL_STATISTICS
TraceRayInlineAccumulateStatistics();
#endif
Output[PixelCoord] = Result;
}