Files
UnrealEngineUWP/Engine/Shaders/Private/GlobalDistanceFieldHeightfields.usf
Daniel Wright 97cf839625 Merging //Tasks/UE4/Private-Reverb-Development-Lumen/... to //UE5/Main/...
Contains all work on Lumen since shipping Reverb in March:
 * New Opaque Final Gather with higher quality in clean architecture and better performance
 * Improved global tracing which reduces leaking
 * New basic Reflections pipeline which respects material Roughness
 * New HZB traces that are more accurate at tracing against the depth buffer
 * Hardware Ray Tracing paths for Lumen shadowing and Final Gather
#rb none

[CL 14274844 by Daniel Wright in ue5-main branch]
2020-09-08 17:44:06 -04:00

307 lines
11 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
GlobalDistanceFieldHeighfields.usf
=============================================================================*/
#include "Common.ush"
#include "GlobalDistanceFieldShared.ush"
#include "HeightfieldLightingShared.ush"
#define GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_X (GLOBAL_DISTANCE_FIELD_PAGE_RESOLUTION_IN_ATLAS / 8)
#define GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_NUM (GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_X * GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_X)
RWStructuredBuffer<uint> RWMarkedHeightfieldPageBuffer;
RWTexture3D<float> RWPageAtlasTexture;
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[256];
[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 * 16;
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 < 128)
{
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 64];
}
GroupMemoryBarrierWithGroupSync();
if (ThreadIndex < 64)
{
GroupMarkedPage[ThreadIndex] = GroupMarkedPage[ThreadIndex] + GroupMarkedPage[ThreadIndex + 64];
}
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], GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_NUM, DestIndex);
RWPageComposeHeightfieldTileBuffer[DestIndex / GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_NUM] = PackedPageGridCoord;
}
}
}
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
void ComposeHeightfieldsIntoPagesCS(
uint3 GroupId : SV_GroupID,
uint3 DispatchThreadId : SV_DispatchThreadID,
uint3 GroupThreadId : SV_GroupThreadID)
{
uint PackedPageTile = ComposeTileBuffer[GroupId.x / GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_NUM];
uint LinearPageGroupOffset = GroupId.x % GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_NUM;
uint3 PageGroupOffset;
PageGroupOffset.x = LinearPageGroupOffset % GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_X;
PageGroupOffset.y = LinearPageGroupOffset / GLOBAL_DISTANCE_FIELD_PAGE_HEIGHFIELD_GROUP_X;
PageGroupOffset.z = 0;
uint3 PageGridCoord;
PageGridCoord.x = PackedPageTile & 0xFF;
PageGridCoord.y = (PackedPageTile >> 8) & 0xFF;
PageGridCoord.z = (PackedPageTile >> 16) & 0xFF;
uint3 TexelCoordInPage = uint3(PageGroupOffset.xy * 8 + GroupThreadId.xy, 0);
uint3 PageCoord = PageGridCoord * GLOBAL_DISTANCE_FIELD_PAGE_RESOLUTION + TexelCoordInPage - 1;
float3 VoxelWorldCenter = PageCoord * PageCoordToVoxelCenterScale + PageCoordToVoxelCenterBias;
uint3 PageTableTextureCoord = PageGridCoordToPageTableTextureCoord(PageGridCoord);
uint PageId = PageTableLayerTexture.Load(int4(PageTableTextureCoord, 0));
uint3 PageAtlasCoord = GlobalDistanceFieldPageLinearIndexToPageAtlasCoord(PageId);
PageAtlasCoord += TexelCoordInPage;
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
{
// 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 * 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, WorldPosition - WorldHeightfieldShadingPosition);
// Limit negative region of a heightfield to a user defined thickness
const float MinInteriorDistance = -HeightfieldThickness;
if (DistanceToHeightfieldPlane < MinInteriorDistance)
{
DistanceToHeightfieldPlane = MinInteriorDistance - DistanceToHeightfieldPlane;
}
const float MinDistance = clamp(DistanceToHeightfieldPlane, -InfluenceRadius, InfluenceRadius);
uint3 PageAtlasCoordZ = PageAtlasCoord + uint3(0, 0, ZIndex);
float PrevMinDistance = DecodeGlobalDistanceFieldPageDistance(RWPageAtlasTexture[PageAtlasCoordZ], InfluenceRadius);
RWPageAtlasTexture[PageAtlasCoordZ] = EncodeGlobalDistanceFieldPageDistance(min(MinDistance, PrevMinDistance), InfluenceRadius);
}
}
}
}