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

390 lines
13 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../Common.ush"
#include "../SceneTextureParameters.ush"
#include "../DeferredShadingCommon.ush"
#include "../ShaderPrint.ush"
#include "../PositionReconstructionCommon.ush"
#include "HairStrandsVisibilityCommon.ush"
#include "HairStrandsVoxelPageCommon.ush"
#include "../ColorMap.ush"
#if SHADER_VOXEL_DEBUG
#define VOXEL_TRAVERSAL_DEBUG 0
#define VOXEL_TRAVERSAL_FORCE_MIP_ENABLE 1
#if PERMUTATION_TRAVERSAL == 1
#define VOXEL_TRAVERSAL_TYPE VOXEL_TRAVERSAL_LINEAR_MIPMAP
#else
#define VOXEL_TRAVERSAL_TYPE VOXEL_TRAVERSAL_LINEAR
#endif
#include "HairStrandsVoxelPageTraversal.ush"
float2 OutputResolution;
uint MacroGroupId;
uint MacroGroupCount;
uint MaxTotalPageIndexCount;
Texture2D<float> SceneDepthBeforeCompositionTexture;
RWTexture2D<float4> OutputTexture;
Buffer<uint> TotalValidPageCounter;
#define VOXEL_BLOCK 0
#define VOXEL_SMOOTH 1
#define VOXEL_FILTERING VOXEL_BLOCK
uint GetVoxelPageIndex(uint3 InPageIndexCoord, uint3 InPageIndexResolution, uint InLinearPageIndexOffset)
{
const uint LinearPageIndexCoord = CoordToIndex(InPageIndexCoord, InPageIndexResolution, InLinearPageIndexOffset);
return VirtualVoxel.PageIndexBuffer.Load(LinearPageIndexCoord);
}
FFontColor GetOccupancyColor(float In)
{
float3 Color = lerp(float3(0, 1, 0), float3(1, 0, 0), saturate(In));
return InitFontColor(Color);
}
[numthreads(8, 8, 1)]
void MainCS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
const float2 PixelCoord = DispatchThreadId.xy + 0.5f;
const float2 UV = PixelCoord / float2(OutputResolution);
const FVirtualVoxelNodeDesc NodeDesc = UnpackVoxelNode(VirtualVoxel.NodeDescBuffer[MacroGroupId], VirtualVoxel.PageResolution);
const bool bIsNodeValid = all(NodeDesc.PageIndexResolution != 0);
const bool bPrint = all(uint2(PixelCoord) == 0);
// Draw macro group AABB & debug infos
if (bPrint)
{
const uint TotalPageIndexCount = MaxTotalPageIndexCount;
const uint TotalPageCount = VirtualVoxel.PageCountResolution.x * VirtualVoxel.PageCountResolution.y * VirtualVoxel.PageCountResolution.z;
const uint TotalAllocatedValidPageCount = TotalValidPageCounter.Load(0);
uint TotalAllocatedPageCount = 0;
for (uint MacroGroupIt = 0; MacroGroupIt < MacroGroupCount; ++MacroGroupIt)
{
const FPackedVirtualVoxelNodeDesc LocalPackedNode = VirtualVoxel.NodeDescBuffer[MacroGroupIt];
const FVirtualVoxelNodeDesc LocalNodeDesc = UnpackVoxelNode(LocalPackedNode, VirtualVoxel.PageResolution);
TotalAllocatedPageCount += LocalNodeDesc.PageIndexResolution.x * LocalNodeDesc.PageIndexResolution.y * LocalNodeDesc.PageIndexResolution.z;
}
AddAABBTWS(NodeDesc.TranslatedWorldMinAABB, NodeDesc.TranslatedWorldMaxAABB, ColorOrange);
// General information
// General
// Voxel World size :
// Page Resolution :
// Page Count Resolution :
// Page Texture Resolution :
//
// Total Allocatled Page Index :
// Total Page Index :
// Total Page Index Occupancy :
//
// Total Allocated Page :
// Total Page :
// Total Page Occupancy :
if (MacroGroupId == 0)
{
FShaderPrintContext Context = InitShaderPrintContext(true, uint2(50, 100));
// Adaptive voxels
Print(Context, TEXT("Alloc. Feedback "), FontOrange);
if (VirtualVoxel.AllocationFeedbackEnable)
{
Print(Context, TEXT("True"), FontGreen);
}
else
{
Print(Context, TEXT("False"), FontRed);
}
Newline(Context);
// Actual voxel/pages size & resolution
Print(Context, TEXT("GPU Curr. Voxel Size "), FontOrange);
Print(Context, VirtualVoxel.CurrGPUMinVoxelSize[0], FontEmerald);
Newline(Context);
Print(Context, TEXT("GPU Next. Voxel Size "));
Print(Context, VirtualVoxel.NextGPUMinVoxelSize[0]);
Newline(Context);
Print(Context, TEXT("CPU Min. Voxel Size "));
Print(Context, VirtualVoxel.CPUMinVoxelWorldSize);
Newline(Context);
Print(Context, TEXT("Page Res "));
Print(Context, VirtualVoxel.PageResolution);
Newline(Context);
Print(Context, TEXT("Page Count Res "));
Print(Context, VirtualVoxel.PageCountResolution.x);
Print(Context, VirtualVoxel.PageCountResolution.y);
Print(Context, VirtualVoxel.PageCountResolution.z);
Newline(Context);
Print(Context, TEXT("Page Texture Res "), FontEmerald);
Print(Context, VirtualVoxel.PageTextureResolution.x, FontEmerald);
Print(Context, VirtualVoxel.PageTextureResolution.y, FontEmerald);
Print(Context, VirtualVoxel.PageTextureResolution.z, FontEmerald);
Newline(Context);
// Total page indices stats
Newline(Context);
Print(Context, TEXT("Total Allocated Page Index "));
Print(Context, TotalAllocatedPageCount);
Newline(Context);
Print(Context, TEXT("Total Page Index "));
Print(Context, TotalPageIndexCount);
Newline(Context);
const float PageIndexOccupancy = TotalAllocatedPageCount / float(TotalPageIndexCount);
Print(Context, TEXT("Page Index Occupancy "), FontOrange);
Print(Context, PageIndexOccupancy * 100.f, GetOccupancyColor(PageIndexOccupancy));
Newline(Context);
// Total pages stats
Newline(Context);
Print(Context, TEXT("Total Allocated Valid Page "));
Print(Context, TotalAllocatedValidPageCount);
Newline(Context);
Print(Context, TEXT("Total Page "));
Print(Context, TotalPageCount);
Newline(Context);
const float PageOccupancy = TotalAllocatedValidPageCount / float(TotalPageCount);
Print(Context, TEXT("Page Occupancy "), FontOrange);
Print(Context, PageOccupancy * 100.f, GetOccupancyColor(PageOccupancy));
Newline(Context);
Print(Context, TEXT("Translated world offset "), FontOrange);
Print(Context, VirtualVoxel.TranslatedWorldOffset);
Newline(Context);
}
// MacroGroupId XX
// Page Index Resolution: X Y Z (Linear/Total - %)
// Virtual Resolution : X Y Z
// Page Index Offset : O
if (MacroGroupId == 0)
{
FShaderPrintContext Context = InitShaderPrintContext(true, uint2(50, 420));
Print(Context, TEXT("Macro Group "), FontOrange);
Newline(Context);
Print(Context, TEXT(" Virtual Res X "), FontEmerald);
Newline(Context);
Print(Context, TEXT(" Virtual Res Y "), FontEmerald);
Newline(Context);
Print(Context, TEXT(" Virtual Res Z "), FontEmerald);
Newline(Context);
Newline(Context);
Print(Context, TEXT(" Page Index Res X "));
Newline(Context);
Print(Context, TEXT(" Page Index Res Y "));
Newline(Context);
Print(Context, TEXT(" Page Index Res Z "));
Newline(Context);
Newline(Context);
Print(Context, TEXT(" Page Index Offset "));
Newline(Context);
Newline(Context);
Print(Context, TEXT(" Voxel World Size "));
Newline(Context);
}
{
FShaderPrintContext Context = InitShaderPrintContext(true, uint2(250 + MacroGroupId * 35, 420));
Print(Context, MacroGroupId, FontOrange);
Newline(Context);
Print(Context, NodeDesc.VirtualResolution.x, FontEmerald);
Newline(Context);
Print(Context, NodeDesc.VirtualResolution.y, FontEmerald);
Newline(Context);
Print(Context, NodeDesc.VirtualResolution.z, FontEmerald);
Newline(Context);
Newline(Context);
Print(Context, NodeDesc.PageIndexResolution.x, FontYellow);
Newline(Context);
Print(Context, NodeDesc.PageIndexResolution.y, FontYellow);
Newline(Context);
Print(Context, NodeDesc.PageIndexResolution.z, FontYellow);
Newline(Context);
Newline(Context);
// Offset of 1 line for every other voxel size, to avoid super-position with large float number
const bool bAddLine = (MacroGroupId & 1) == 1;
if (bAddLine) { Newline(Context); }
Print(Context, NodeDesc.PageIndexOffset, FontSilver);
Newline(Context);
Newline(Context);
Print(Context, NodeDesc.VoxelWorldSize, FontSilver);
Newline(Context);
}
}
// Draw widgets
bool bDrawVoxel = true;
bool bDrawPage = false;
int ForcedMipLevel = -1;
{
FShaderPrintContext WidgetContext = InitShaderPrintContext(MacroGroupId == 0 && bPrint, uint2(500, 100));
bDrawVoxel = AddCheckbox(WidgetContext, TEXT("Draw Voxels"), true, FontWhite); Newline(WidgetContext);
bDrawPage = AddCheckbox(WidgetContext, TEXT("Draw Pages"), false, FontWhite); Newline(WidgetContext);
bool bForceMipLevel = AddCheckbox(WidgetContext, TEXT("Force MIP"), false, FontWhite); Newline(WidgetContext);
if (bForceMipLevel)
{
ForcedMipLevel = 8u * AddSlider(WidgetContext, TEXT("MIP"), 0, FontWhite);
ForcedMipLevel = clamp(ForcedMipLevel, 0, int(VirtualVoxel.PageResolutionLog2));
Print(WidgetContext, ForcedMipLevel, FontWhite, 1, 1);
Print(WidgetContext, TEXT("/"), FontWhite);
Print(WidgetContext, VirtualVoxel.PageResolutionLog2, FontWhite, 1, 1);
Newline(WidgetContext);
}
}
bool bIsValid = false;
float3 HitColor = 0;
if (bDrawPage)
{
// Reverse-Z
const float SceneDepth = ConvertFromDeviceZ(SceneDepthBeforeCompositionTexture.Load(uint3(PixelCoord, 0)));
const float3 O = PrimaryView.TranslatedWorldCameraOrigin;
const float3 E = ReconstructTranslatedWorldPositionFromDepth(UV, SceneDepth);
const float3 D = (E - O);
float PixelRadius = -1;
const float2 HitT = LineBoxIntersect(O, E, NodeDesc.TranslatedWorldMinAABB, NodeDesc.TranslatedWorldMaxAABB);
float AccDensity = 0;
if (HitT.x < HitT.y)
{
// Use different offseting to see either:
// * Individual voxel (for debugging mainly)
// * Smoothed voxel (as used for transmittance computation)
#if VOXEL_FILTERING == VOXEL_BLOCK
const float3 Offset = 0;
const float Dither = InterleavedGradientNoise(PixelCoord.xy, 1);
#endif
#if VOXEL_FILTERING == VOXEL_SMOOTH
const float3 Offset = float3(InterleavedGradientNoise(PixelCoord.xy, 1), InterleavedGradientNoise(PixelCoord.xy, 2), InterleavedGradientNoise(PixelCoord.xy, 3));
const float Dither = 0;
#endif
// Intersect the indirection table to see if a brick is empty or not
const uint MaxStep = 256;
const float Delta = (HitT.y-HitT.x)/float(MaxStep);
for (uint StepIt=0; StepIt<MaxStep; ++StepIt)
{
const float3 HitP = Offset + O + ((Dither+StepIt)*Delta + HitT.x) * D;
const int3 PageIndexCoord = PositionToCoord(HitP, NodeDesc.TranslatedWorldMinAABB, NodeDesc.TranslatedWorldMaxAABB, NodeDesc.PageIndexResolution);
const uint PageIndex = GetVoxelPageIndex(PageIndexCoord, NodeDesc.PageIndexResolution, NodeDesc.PageIndexOffset);
if (PageIndex != INVALID_VOXEL_PAGE_INDEX)
{
const uint3 PageCoord = IndexToCoord(PageIndex, VirtualVoxel.PageCountResolution);
AccDensity = 1;
bIsValid = true;
HitColor = PageIndexCoord / 12.f;
break;
}
}
}
}
else if (bDrawVoxel)
{
const bool bIsPixelEnable = all(int2(PixelCoord) == GetCursorPos());
FHairTraversalResult TraversalResult = (FHairTraversalResult)0;
const float DistanceThreshold = 10000;
const bool bDebugEnabled = false;
const float3 SampleRandom = GetHairVoxelJitter(PixelCoord, View.StateFrameIndexMod8, VirtualVoxel.JitterMode);
const float SceneDepth = ConvertFromDeviceZ(SceneDepthBeforeCompositionTexture.Load(uint3(PixelCoord, 0)));
const float3 TranslatedWP0 = PrimaryView.TranslatedWorldCameraOrigin;
const float3 TranslatedWP1 = ReconstructTranslatedWorldPositionFromDepth(UV, SceneDepth);
FVirtualVoxelCommonDesc CommonDesc;
CommonDesc.PageCountResolution = VirtualVoxel.PageCountResolution;
CommonDesc.PageTextureResolution= VirtualVoxel.PageTextureResolution;
CommonDesc.PageResolution = VirtualVoxel.PageResolution;
CommonDesc.PageResolutionLog2 = VirtualVoxel.PageResolutionLog2;
if (bIsNodeValid)
{
FHairTraversalSettings TraversalSettings = InitHairTraversalSettings();
TraversalSettings.DensityScale = VirtualVoxel.DensityScale;
TraversalSettings.CountThreshold = GetOpaqueVoxelValue();
TraversalSettings.DistanceThreshold = DistanceThreshold;
TraversalSettings.bDebugEnabled = bDebugEnabled;
TraversalSettings.SteppingScale = VirtualVoxel.SteppingScale_Shadow;
TraversalSettings.Random = SampleRandom;
TraversalSettings.TanConeAngle = 0;
TraversalSettings.bIsPrimaryRay = true;
TraversalSettings.PixelRadius = -1;
TraversalSettings.ForcedMip = ForcedMipLevel;
TraversalSettings.bDebugEnabled = false; //bIsPixelEnable;
TraversalResult = ComputeHairCountVirtualVoxel(
TranslatedWP0,
TranslatedWP1,
CommonDesc,
NodeDesc,
VirtualVoxel.PageIndexBuffer,
VirtualVoxel.PageTexture,
TraversalSettings);
HitColor = GetHSVDebugColor(saturate(TraversalResult.HairCount / 16));
bIsValid = TraversalResult.HairCount > 0;
}
if (bIsPixelEnable && bIsValid)
{
FShaderPrintContext Context = InitShaderPrintContext(true, uint2(50, 50));
Print(Context, TEXT("X, Y "));
Print(Context, GetCursorPos());
Newline(Context);
Print(Context, TEXT("T.Count "));
Print(Context, TraversalResult.HairCount);
Newline(Context);
Print(Context, TEXT("T.Visibility "));
Print(Context, TraversalResult.Visibility);
Newline(Context);
}
}
if (bIsValid)
{
OutputTexture[DispatchThreadId.xy] = float4(HitColor, 1);
}
}
#endif // SHADER_VOXEL_DEBUG