Files
UnrealEngine/Engine/Shaders/Private/Nanite/Voxel/AutoVoxel.usf
2025-05-18 13:04:45 +08:00

201 lines
5.5 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../../Common.ush"
#include "../../SceneTexturesCommon.ush"
#include "../../HashTable.ush"
#include "../../WaveOpUtil.ush"
#include "../../ShaderPrint.ush"
#include "Voxel.ush"
#include "Brick.ush"
StructuredBuffer< uint > IndexBuffer;
RWStructuredBuffer< uint > RWIndexBuffer;
RWByteAddressBuffer RWBlockBuffer;
int4 DepthToVoxel( uint2 PixelPos, float Depth )
{
//Depth = max( Depth, 1e-4 );
float3 TranslatedWorldPosition = SvPositionToTranslatedWorld( float4( PixelPos + 0.5, Depth, 1 ) );
float3 VoxelPos = TranslatedWorldPosition / VoxelSize;
float Distance = length( TranslatedWorldPosition - View.TranslatedWorldCameraOrigin );
//float Distance = max3( TranslatedWorldPosition.x, TranslatedWorldPosition.y, TranslatedWorldPosition.z );
// TODO output resolution instead of render
float PixelsPerVoxel = 0.5;
float DistanceFactor = 2.0 * PixelsPerVoxel / ( VoxelSize * View.ViewToClip[1][1] * View.ViewSizeAndInvSize.y );
float Level = log2( Distance * DistanceFactor );
Level = floor( max( Level, 0 ) );
VoxelPos = floor( VoxelPos * exp2( -Level ) );
return int4( VoxelPos, Level );
}
void AddVoxelToBlock( uint BlockOffset, uint3 Voxel )
{
uint VoxelIndex = Voxel.x + Voxel.y * 4 + Voxel.z * 16;
uint HighInt = VoxelIndex >= 32;
uint VoxelMask = 1u << ( VoxelIndex - HighInt * 32 );
RWBlockBuffer.InterlockedOr( 8 * BlockOffset + 4 * HighInt, VoxelMask );
}
[numthreads(8, 8, 1)]
void VisibleBricksHash(
uint2 PixelPos : SV_DispatchThreadID,
uint GroupIndex : SV_GroupIndex )
{
bool bInsideViewport = all( PixelPos < View.ViewSizeAndInvSize.xy );
BRANCH
if( bInsideViewport )
{
float Depth = SceneTexturesStruct.SceneDepthTexture.Load( int3( PixelPos, 0 ) ).r;
int4 Voxel = DepthToVoxel( PixelPos, Depth );
uint3 BrickKey = EncodeBrickKey( Voxel.xyz >> uint( BrickSizeLog2 ), Voxel.w );
//uint3 Hash = Rand3DPCG32( BrickKey );
uint4 Hash = Rand4DPCG32( int4( Voxel.xyz >> uint( BrickSizeLog2 ), Voxel.w ) );
uint HashKey = Hash.x;
uint HashIndex = Hash.y;
bool bAdded = HashTableAdd( HashKey, HashIndex );
FBrick Brick;
Brick.Key = BrickKey;
Brick.BlockOffset = HashIndex;
uint BrickIndex = HashIndex;
if( bAdded )
{
//if( all( PixelPos == 0 ) )
if(1)
{
// Add to count
WaveInterlockedAddScalar_( RWDispatchIndirectArgs[3], 1, BrickIndex );
//WaveInterlockedAddScalar( RWDispatchIndirectArgs[0], 1 );
//WaveInterlockedAddScalarInGroups( RWDispatchIndirectArgs[3], RWDispatchIndirectArgs[0], 64, 1, BrickIndex );
}
else
{
BrickIndex = RWBrickBuffer.IncrementCounter();
}
RWIndexBuffer[ HashIndex ] = BrickIndex;
RWBrickBuffer[ BrickIndex ] = Brick;
}
Voxel.xyz &= uint( BrickSize - 1 );
//Voxel.xyz &= (int)BrickSize - 1;
AddVoxelToBlock( Brick.BlockOffset, Voxel.xyz / ( BrickSize / 4 ) );
}
}
[numthreads(32, 1, 1)]
void FillArgs( uint GroupIndex : SV_GroupIndex )
{
if( GroupIndex == 0 )
{
#if 1
//uint NumBricks = RWBrickBuffer.IncrementCounter();
uint NumBricks = RWDispatchIndirectArgs[3];
NumBricks = min( NumBricks, 1u << 25 );
FShaderPrintContext Context = InitShaderPrintContext(true, float2(0.65, 0.05));
Print(Context, TEXT("Voxel"), FontOrange);
Newline(Context);
Print(Context, TEXT("NumBricks: "));
Print(Context, NumBricks);
RWDispatchIndirectArgs[0] = ( NumBricks + 63 ) / 64;
RWDispatchIndirectArgs[1] = 1;
RWDispatchIndirectArgs[2] = 1;
RWDispatchIndirectArgs[3] = NumBricks;
#else
uint NumBricks = RWDispatchIndirectArgs[3];
RWDispatchIndirectArgs[0] = NumBricks;
RWDispatchIndirectArgs[1] = 1;
RWDispatchIndirectArgs[2] = 1;
RWDispatchIndirectArgs[3] = NumBricks;
#endif
SetDrawIndirectArgs( NumBricks );
}
}
[numthreads(64, 1, 1)]
void AllocBlocks(
uint BrickIndex : SV_DispatchThreadID,
uint GroupIndex : SV_GroupIndex )
{
uint NumBricks = GetNumBricks();
NumBricks = min( NumBricks, 1u << 25 );
uint BlockOffset = 0;
uint NumBlocks = 0;
uint2 Block = 0;
if( BrickIndex < NumBricks )
{
BlockOffset = RWBrickBuffer[ BrickIndex ].BlockOffset;
Block = BlockBuffer.Load2( 8 * BlockOffset );
NumBlocks = 1 + countbits( Block.x ) + countbits( Block.y );
// Alloc space for all blocks
WaveInterlockedAdd_( RWDrawIndirectArgs[5], NumBlocks, BlockOffset );
RWBrickBuffer[ BrickIndex ].BlockOffset = BlockOffset;
RWBlockBuffer.Store2( 8 * BlockOffset, Block );
}
if( BrickIndex == 0 )
{
SetDrawIndirectArgs( NumBricks );
}
}
[numthreads(8, 8, 1)]
void FillBlocks( uint2 PixelPos : SV_DispatchThreadID )
{
bool bInsideViewport = all( PixelPos < View.ViewSizeAndInvSize.xy );
BRANCH
if( bInsideViewport )
{
float Depth = SceneTexturesStruct.SceneDepthTexture.Load( int3( PixelPos, 0 ) ).r;
int4 Voxel = DepthToVoxel( PixelPos, Depth );
uint3 BrickKey = EncodeBrickKey( Voxel.xyz >> uint( BrickSizeLog2 ), Voxel.w );
uint4 Hash = Rand4DPCG32( int4( Voxel.xyz >> uint( BrickSizeLog2 ), Voxel.w ) );
//uint3 Hash = Rand3DPCG32( BrickKey );
uint HashKey = Hash.x;
uint HashIndex = Hash.y;
HashTableFind( HashKey, HashIndex );
uint BrickIndex = IndexBuffer[ HashIndex ];
FBrick Brick = BrickBuffer[ BrickIndex ];
uint3 Block = ( Voxel.xyz >> 2 ) & 3;
uint VoxelIndex = Block.x + Block.y * 4 + Block.z * 16;
uint VoxelMask = 1u << ( VoxelIndex & 31 );
uint2 RootBlock = RWBlockBuffer.Load2( 8 * Brick.BlockOffset );
uint BlockOffset = PrefixSum64( RootBlock, VoxelIndex, VoxelMask );
AddVoxelToBlock( Brick.BlockOffset + 1 + BlockOffset, Voxel.xyz & 3 );
}
}