You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* Decreased Global Distance Field border from full voxel to half voxel and decreased page size from 16 to 8. This removes ~30% of pages, saving memory and improving update speed * Half texel border requires to compute gradients using 8 page table fetches, but it didn�t influence Lumen tracing performance on console * Smaller pages put some pressure on culling and other passes. Culling grid was switch from per page to per 4x4x4 pages. Overall full GDF update speed in FortGPUTestBed decreased from 5.89ms to 4.57ms * Switched page table format to UInt32 in order to support larger Global Distance Field resolutions * Moved all GlobalDistanceField shaders into /DistanceField/* folder, in future we should move other distance field shaders there * Moved GlobalDistanceField page stats from r.Lumen.Visualize.Stats in Lumen code to r.GlobalDistanceField.Debug in GlobalDistanceField code * Fixed Lumen normal visualization when only Global Distance Field tracing is enabled #preflight 62630427006fa20b683b405a [FYI] Tiago.Costa, Daniel.Wright #ROBOMERGE-AUTHOR: krzysztof.narkowicz #ROBOMERGE-SOURCE: CL 19873116 via CL 19873429 via CL 19874251 #ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v940-19807014) [CL 19878047 by krzysztof narkowicz in ue5-main branch]
300 lines
11 KiB
Plaintext
300 lines
11 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "../Common.ush"
|
|
#include "../HeightfieldLightingShared.ush"
|
|
#include "GlobalDistanceFieldShared.ush"
|
|
#include "GlobalDistanceFieldUtils.ush"
|
|
|
|
RWStructuredBuffer<uint> RWMarkedHeightfieldPageBuffer;
|
|
RWTexture3D<UNORM float> RWPageAtlasTexture;
|
|
RWTexture3D<UNORM float> RWCoverageAtlasTexture;
|
|
|
|
StructuredBuffer<uint> MarkedHeightfieldPageBuffer;
|
|
StructuredBuffer<uint> PageUpdateTileBuffer;
|
|
StructuredBuffer<uint> ComposeTileBuffer;
|
|
Texture3D<uint> PageTableLayerTexture;
|
|
|
|
float3 PageCoordToPageWorldCenterScale;
|
|
float3 PageCoordToPageWorldCenterBias;
|
|
float3 PageCoordToVoxelCenterScale;
|
|
float3 PageCoordToVoxelCenterBias;
|
|
float3 PageWorldExtent;
|
|
float4 ClipmapVolumeWorldToUVAddAndMul;
|
|
float3 InvPageGridResolution;
|
|
uint3 PageGridResolution;
|
|
uint PageTableClipmapOffsetZ;
|
|
float ClipmapVoxelExtent;
|
|
float InfluenceRadius;
|
|
float HeightfieldThickness;
|
|
|
|
uint3 PageGridCoordToPageTableTextureCoord(uint3 PageGridCoord)
|
|
{
|
|
float3 PageWorldCenter = PageGridCoord * PageCoordToPageWorldCenterScale + PageCoordToPageWorldCenterBias;
|
|
|
|
float4 WorldToUVAddAndMul = ClipmapVolumeWorldToUVAddAndMul;
|
|
float3 ClipmapUV = frac(PageWorldCenter * WorldToUVAddAndMul.www + WorldToUVAddAndMul.xyz);
|
|
|
|
int3 PageTableTextureCoord = clamp(saturate(ClipmapUV) * PageGridResolution, 0, PageGridResolution - 1) + int3(0, 0, PageTableClipmapOffsetZ);
|
|
return PageTableTextureCoord;
|
|
}
|
|
|
|
groupshared uint GroupMarkedPage[64];
|
|
|
|
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
|
|
void MarkHeightfieldPagesCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 DispatchThreadId : SV_DispatchThreadID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
uint3 VoxelCoord = uint3(GroupThreadId.xy, 0);
|
|
uint ThreadIndex = GroupThreadId.x + GroupThreadId.y * THREADGROUP_SIZE_X;
|
|
uint IndexInPageBuffer = GroupId.x;
|
|
uint PackedPageGridCoord = PageUpdateTileBuffer[IndexInPageBuffer];
|
|
|
|
uint3 PageGridCoord;
|
|
PageGridCoord.x = PackedPageGridCoord & 0xFF;
|
|
PageGridCoord.y = (PackedPageGridCoord >> 8) & 0xFF;
|
|
PageGridCoord.z = (PackedPageGridCoord >> 16) & 0xFF;
|
|
|
|
float3 PageWorldCenter = PageGridCoord * PageCoordToPageWorldCenterScale + PageCoordToPageWorldCenterBias;
|
|
float3 VoxelWorldCenter = PageWorldCenter - PageWorldExtent + VoxelCoord * 2.0f * PageWorldExtent;
|
|
|
|
GroupMarkedPage[ThreadIndex] = 0;
|
|
|
|
uint ValidHeightfieldIndex = 0;
|
|
|
|
LOOP
|
|
for (uint HeightfieldIndex = 0; HeightfieldIndex < NumHeightfields; HeightfieldIndex++)
|
|
{
|
|
float3 LocalPosition = mul(float4(VoxelWorldCenter, 1), GetWorldToLocal(HeightfieldIndex)).xyz;
|
|
float4 MinMaxHeightfieldUV;
|
|
float2 HeightfieldUV = GetHeightfieldUV(HeightfieldIndex, LocalPosition.xy, MinMaxHeightfieldUV);
|
|
|
|
if (all(HeightfieldUV > MinMaxHeightfieldUV.xy) && all(HeightfieldUV < MinMaxHeightfieldUV.zw))
|
|
{
|
|
ValidHeightfieldIndex = HeightfieldIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
float3 LocalPosition = mul(float4(VoxelWorldCenter, 1), GetWorldToLocal(ValidHeightfieldIndex)).xyz;
|
|
float4 MinMaxHeightfieldUV;
|
|
float2 HeightfieldUV = GetHeightfieldUV(ValidHeightfieldIndex, LocalPosition.xy, MinMaxHeightfieldUV);
|
|
|
|
if (all(HeightfieldUV > MinMaxHeightfieldUV.xy) && all(HeightfieldUV < MinMaxHeightfieldUV.zw))
|
|
{
|
|
float3 WorldHeightfieldNormal;
|
|
float HeightfieldVisibility;
|
|
float3 WorldHeightfieldShadingPosition = GetHeightfieldWorldPositionAndNormal(ValidHeightfieldIndex, LocalPosition.xy, HeightfieldUV, WorldHeightfieldNormal, HeightfieldVisibility);
|
|
|
|
if (HeightfieldVisibility > 0.5f) // Skip holes in the heightfield
|
|
{
|
|
float3 WorldPositionNearestZ = VoxelWorldCenter;
|
|
WorldPositionNearestZ.z = clamp(WorldHeightfieldShadingPosition.z, VoxelWorldCenter.z, VoxelWorldCenter.z + GLOBAL_DISTANCE_FIELD_PAGE_RESOLUTION_IN_ATLAS * 2.0f * ClipmapVoxelExtent);
|
|
|
|
// Project the vertical height vector onto the normal of the heightfield directly below the point we are computing the distance field for, use the perpendicular distance
|
|
float DistanceToHeightfieldPlane = dot(WorldHeightfieldNormal, WorldPositionNearestZ - WorldHeightfieldShadingPosition);
|
|
|
|
// Limit negative region of a heightfield to a user defined thickness
|
|
const float MinInteriorDistance = -HeightfieldThickness;
|
|
if (DistanceToHeightfieldPlane < MinInteriorDistance)
|
|
{
|
|
DistanceToHeightfieldPlane = MinInteriorDistance - DistanceToHeightfieldPlane;
|
|
}
|
|
|
|
if (DistanceToHeightfieldPlane > -InfluenceRadius && DistanceToHeightfieldPlane < InfluenceRadius)
|
|
{
|
|
GroupMarkedPage[ThreadIndex] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (ThreadIndex < 32)
|
|
{
|
|
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 32];
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (ThreadIndex < 16)
|
|
{
|
|
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 16];
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (ThreadIndex < 8)
|
|
{
|
|
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 8];
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (ThreadIndex < 4)
|
|
{
|
|
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 4];
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (ThreadIndex < 2)
|
|
{
|
|
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 2];
|
|
}
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (ThreadIndex == 0)
|
|
{
|
|
if (GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 1] > 0)
|
|
{
|
|
RWMarkedHeightfieldPageBuffer[IndexInPageBuffer] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
RWBuffer<uint> RWBuildHeightfieldComposeTilesIndirectArgBuffer;
|
|
RWBuffer<uint> RWPageComposeHeightfieldIndirectArgBuffer;
|
|
Buffer<uint> PageUpdateIndirectArgBuffer;
|
|
|
|
[numthreads(1, 1, 1)]
|
|
void BuildHeightfieldComposeTilesIndirectArgBufferCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 DispatchThreadId : SV_DispatchThreadID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
if (DispatchThreadId.x == 0)
|
|
{
|
|
const uint TileNum = PageUpdateIndirectArgBuffer[0];
|
|
|
|
RWBuildHeightfieldComposeTilesIndirectArgBuffer[0] = (TileNum + 63) / 64;
|
|
RWBuildHeightfieldComposeTilesIndirectArgBuffer[1] = 1;
|
|
RWBuildHeightfieldComposeTilesIndirectArgBuffer[2] = 1;
|
|
|
|
RWPageComposeHeightfieldIndirectArgBuffer[0] = 0;
|
|
RWPageComposeHeightfieldIndirectArgBuffer[1] = 1;
|
|
RWPageComposeHeightfieldIndirectArgBuffer[2] = 1;
|
|
}
|
|
}
|
|
|
|
RWStructuredBuffer<uint> RWPageComposeHeightfieldTileBuffer;
|
|
|
|
[numthreads(THREADGROUP_SIZE_X, 1, 1)]
|
|
void BuildHeightfieldComposeTilesCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 DispatchThreadId : SV_DispatchThreadID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
const uint TileIndex = DispatchThreadId.x;
|
|
const uint TileNum = PageUpdateIndirectArgBuffer[0];
|
|
|
|
if (TileIndex < TileNum)
|
|
{
|
|
uint PackedPageGridCoord = PageUpdateTileBuffer[TileIndex];
|
|
bool bMarkedHeightfieldPage = MarkedHeightfieldPageBuffer[TileIndex] > 0;
|
|
|
|
if (bMarkedHeightfieldPage)
|
|
{
|
|
uint DestIndex;
|
|
InterlockedAdd(RWPageComposeHeightfieldIndirectArgBuffer[0], 1, DestIndex);
|
|
RWPageComposeHeightfieldTileBuffer[DestIndex] = PackedPageGridCoord;
|
|
}
|
|
}
|
|
}
|
|
|
|
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
|
|
void ComposeHeightfieldsIntoPagesCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
uint PackedPageTile = ComposeTileBuffer[GroupId.x];
|
|
|
|
uint3 PageGridCoord;
|
|
PageGridCoord.x = PackedPageTile & 0xFF;
|
|
PageGridCoord.y = (PackedPageTile >> 8) & 0xFF;
|
|
PageGridCoord.z = (PackedPageTile >> 16) & 0xFF;
|
|
|
|
uint3 TexelCoordInPage = uint3(GroupThreadId.xy, 0);
|
|
|
|
float3 PageCoord = PageGridCoord * GLOBAL_DISTANCE_FIELD_PAGE_RESOLUTION + TexelCoordInPage - GLOBAL_DISTANCE_FIELD_PAGE_BORDER;
|
|
float3 VoxelWorldCenter = PageCoord * PageCoordToVoxelCenterScale + PageCoordToVoxelCenterBias;
|
|
|
|
uint3 PageTableTextureCoord = PageGridCoordToPageTableTextureCoord(PageGridCoord);
|
|
uint PageId = PageTableLayerTexture.Load(int4(PageTableTextureCoord, 0));
|
|
uint3 PageAtlasCoord = GlobalDistanceFieldPageLinearIndexToPageAtlasOffset(PageId) * GLOBAL_DISTANCE_FIELD_PAGE_RESOLUTION_IN_ATLAS;
|
|
PageAtlasCoord += TexelCoordInPage;
|
|
|
|
uint ValidHeightfieldIndex = NumHeightfields;
|
|
|
|
LOOP
|
|
for (uint HeightfieldIndex = 0; HeightfieldIndex < NumHeightfields; HeightfieldIndex++)
|
|
{
|
|
float3 LocalPosition = mul(float4(VoxelWorldCenter, 1), GetWorldToLocal(HeightfieldIndex)).xyz;
|
|
float4 MinMaxHeightfieldUV;
|
|
float2 HeightfieldUV = GetHeightfieldUV(HeightfieldIndex, LocalPosition.xy, MinMaxHeightfieldUV);
|
|
|
|
if (all(HeightfieldUV >= MinMaxHeightfieldUV.xy) && all(HeightfieldUV <= MinMaxHeightfieldUV.zw))
|
|
{
|
|
ValidHeightfieldIndex = HeightfieldIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ValidHeightfieldIndex < NumHeightfields)
|
|
{
|
|
float3 LocalPosition = mul(float4(VoxelWorldCenter, 1), GetWorldToLocal(ValidHeightfieldIndex)).xyz;
|
|
float4 MinMaxHeightfieldUV;
|
|
float2 HeightfieldUV = GetHeightfieldUV(ValidHeightfieldIndex, LocalPosition.xy, MinMaxHeightfieldUV);
|
|
|
|
if (all(HeightfieldUV >= MinMaxHeightfieldUV.xy) && all(HeightfieldUV <= MinMaxHeightfieldUV.zw))
|
|
{
|
|
float3 WorldHeightfieldNormal;
|
|
float HeightfieldVisibility;
|
|
float3 WorldHeightfieldShadingPosition = GetHeightfieldWorldPositionAndNormal(ValidHeightfieldIndex, LocalPosition.xy, HeightfieldUV, WorldHeightfieldNormal, HeightfieldVisibility);
|
|
|
|
if (HeightfieldVisibility > 0.5f) // Skip holes in the heightfield
|
|
{
|
|
// Compute distance for all Z values of the update region
|
|
LOOP
|
|
for (uint ZIndex = 0; ZIndex < GLOBAL_DISTANCE_FIELD_PAGE_RESOLUTION_IN_ATLAS; ++ZIndex)
|
|
{
|
|
float3 WorldPosition = VoxelWorldCenter.xyz + float3(0.0f, 0.0f, ZIndex * PageCoordToVoxelCenterScale.z);
|
|
|
|
// Project the vertical height vector onto the normal of the heightfield directly below the point we are computing the distance field for, use the perpendicular distance
|
|
float DistanceToHeightfieldPlane = dot(WorldHeightfieldNormal, WorldPosition - WorldHeightfieldShadingPosition);
|
|
|
|
// Limit negative region of a heightfield to a user defined thickness
|
|
const float MinInteriorDistance = -HeightfieldThickness;
|
|
if (DistanceToHeightfieldPlane < MinInteriorDistance)
|
|
{
|
|
DistanceToHeightfieldPlane = MinInteriorDistance - DistanceToHeightfieldPlane;
|
|
}
|
|
|
|
float HeightfieldMinDistance = clamp(DistanceToHeightfieldPlane, -InfluenceRadius, InfluenceRadius);
|
|
|
|
const uint3 PageAtlasCoordZ = PageAtlasCoord + uint3(0, 0, ZIndex);
|
|
|
|
float PreviousDistanceField = DecodeGlobalDistanceFieldPageDistance(RWPageAtlasTexture[PageAtlasCoordZ], InfluenceRadius);
|
|
float MinDistance = min(HeightfieldMinDistance, PreviousDistanceField);
|
|
|
|
RWPageAtlasTexture[PageAtlasCoordZ] = EncodeGlobalDistanceFieldPageDistance(MinDistance, InfluenceRadius);
|
|
|
|
#if COMPOSITE_COVERAGE_ATLAS
|
|
uint3 TexelCoordInPageWithZ = uint3(TexelCoordInPage.xy, ZIndex);
|
|
bool bThreadWritesCoverage = all(TexelCoordInPageWithZ % GLOBAL_DISTANCE_FIELD_COVERAGE_DOWNSAMPLE_FACTOR == 0);
|
|
uint3 CoverageTexelCoordInPage = TexelCoordInPageWithZ / GLOBAL_DISTANCE_FIELD_COVERAGE_DOWNSAMPLE_FACTOR;
|
|
|
|
if (bThreadWritesCoverage && abs(HeightfieldMinDistance) < ClipmapVoxelExtent * DEFAULT_BAND_SIZE
|
|
&& all(CoverageTexelCoordInPage < GLOBAL_DISTANCE_FIELD_COVERAGE_PAGE_RESOLUTION_IN_ATLAS))
|
|
{
|
|
uint3 CoverageAtlasCoord = GlobalDistanceFieldPageLinearIndexToPageAtlasOffset(PageId) * GLOBAL_DISTANCE_FIELD_COVERAGE_PAGE_RESOLUTION_IN_ATLAS + CoverageTexelCoordInPage;
|
|
RWCoverageAtlasTexture[CoverageAtlasCoord] = 1.0f;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |