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

310 lines
7.5 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../../Common.ush"
#include "../../WaveOpUtil.ush"
#include "Brick.ush"
#include "Voxel.ush"
static const uint TileShift = 3; // 8x8
static const uint TileListBufferSize = 1u << 25;
struct FTileListElement
{
float Depth;
//uint Bounds;
uint BrickIndex;
uint NextIndex;
};
struct FTileArrayElement
{
float Depth;
uint BrickIndex;
};
StructuredBuffer< FTileListElement > TileListBuffer;
RWStructuredBuffer< FTileListElement > RWTileListBuffer;
StructuredBuffer< FTileArrayElement > TileArrayBuffer;
RWStructuredBuffer< FTileArrayElement > RWTileArrayBuffer;
Texture2D< uint > TileHead;
RWTexture2D< uint > RWTileHead;
Texture2D< uint > TileCount;
RWTexture2D< uint > RWTileCount;
Texture2D< uint > TileOffset;
RWTexture2D< uint > RWTileOffset;
[numthreads(64, 1, 1)]
void BinBricksInTiles( uint BrickIndex : SV_DispatchThreadID )
{
uint NumBricks = GetNumBricks();
if( BrickIndex < NumBricks )
{
FBrick Brick = BrickBuffer[ BrickIndex ];
float3 BrickPos;
float CubeSize;
DecodeBrickKey( Brick.Key, BrickPos, CubeSize );
float3 WorldMin = BrickPos * CubeSize;
float3 WorldMax = WorldMin + CubeSize;
uint2 RootBlock = BlockBuffer.Load2( 8 * Brick.BlockOffset );
uint3 BrickMin, BrickMax;
BlockBounds( RootBlock, BrickMin, BrickMax );
BrickMax--;
uint BrickBounds;
BrickBounds = BrickMin.x;
BrickBounds |= BrickMin.y << 2;
BrickBounds |= BrickMin.z << 4;
BrickBounds |= BrickMax.x << 6;
BrickBounds |= BrickMax.y << 8;
BrickBounds |= BrickMax.z << 10;
if(1)
{
BrickMax++;
float3 UnitMin = BrickMin * 0.25;
float3 UnitMax = BrickMax * 0.25;
float3 NewWorldMin = lerp( WorldMin, WorldMax, UnitMin );
float3 NewWorldMax = lerp( WorldMin, WorldMax, UnitMax );
WorldMin = NewWorldMin;
WorldMax = NewWorldMax;
}
float3 Bounds[2] = { WorldMin, WorldMax };
// Screen rect from bounds
float3 RectMin = float3( 1, 1, 1 );
float3 RectMax = float3( -1, -1, -1 );
UNROLL for( uint i = 0; i < 8; i++ )
{
float3 PointWorld;
PointWorld.x = Bounds[ (i >> 0) & 1 ].x;
PointWorld.y = Bounds[ (i >> 1) & 1 ].y;
PointWorld.z = Bounds[ (i >> 2) & 1 ].z;
float4 PointClip = mul( float4( PointWorld, 1 ), View.TranslatedWorldToClip );
float3 PointScreen = PointClip.xyz / PointClip.w;
RectMin = min( RectMin, PointScreen );
RectMax = max( RectMax, PointScreen );
}
float4 RectUV = saturate( float4( RectMin.xy, RectMax.xy ) * float2( 0.5, -0.5 ).xyxy + 0.5 ).xwzy;
uint4 RectPixels = uint4( floor( RectUV.xy * View.ViewSizeAndInvSize.xy ), ceil( RectUV.zw * View.ViewSizeAndInvSize.xy ) );
uint4 RectTiles = RectPixels >> TileShift;
float Depth = ConvertFromDeviceZ( RectMax.z );
for( uint x = RectTiles.x; x <= RectTiles.z; x++ )
{
for( uint y = RectTiles.y; y <= RectTiles.w; y++ )
{
uint2 TileIndex = { x, y };
// Add to linked list
//uint ListIndex = RWTileListBuffer.IncrementCounter();
uint ListIndex = 0;
WaveInterlockedAddScalar_( RWDispatchIndirectArgs[4], 1, ListIndex );
if( ListIndex < TileListBufferSize )
{
FTileListElement Element = { Depth, BrickIndex, 0 };
//FTileListElement Element = { BrickBounds, BrickIndex, 0 };
InterlockedExchange( RWTileHead[ TileIndex ], ListIndex + 1, Element.NextIndex ); // Zero is reserved
InterlockedAdd( RWTileCount[ TileIndex ], 1 );
RWTileListBuffer[ ListIndex ] = Element;
}
}
}
}
}
[numthreads(8, 8, 1)]
void BuildTileArrays(
uint2 TileIndex : SV_DispatchThreadID,
uint GroupIndex : SV_GroupIndex )
{
uint ArrayNum = TileCount[ TileIndex ];
uint ArrayOffset = 0;
if( ArrayNum )
{
// Alloc space
WaveInterlockedAdd_( RWDispatchIndirectArgs[3], ArrayNum, ArrayOffset );
RWTileOffset[ TileIndex ] = ArrayOffset;
}
// Convert linked list to array
uint ArrayIndex = ArrayOffset;
uint ListIndex = TileHead[ TileIndex ];
while( ListIndex )
{
FTileListElement This = TileListBuffer[ ListIndex - 1 ];
ListIndex = This.NextIndex;
// Insertion sort
uint i = ArrayIndex++;
while( i > ArrayOffset )
{
FTileArrayElement Prev = RWTileArrayBuffer[ i - 1 ];
if( This.Depth >= Prev.Depth )
break;
RWTileArrayBuffer[i] = Prev;
i--;
}
RWTileArrayBuffer[i].Depth = This.Depth;
RWTileArrayBuffer[i].BrickIndex = This.BrickIndex;
}
}
RWTexture2D< float4 > OutSceneColor;
[numthreads(8, 8, 1)]
void RayCastTiles( uint2 PixelPos : SV_DispatchThreadID )
{
float4 OutColor = 0;
bool bInsideViewport = all( PixelPos < View.ViewSizeAndInvSize.xy );
BRANCH
if( !bInsideViewport )
return;
FRay Ray = GetViewRay( (float2)PixelPos + 0.5 );
uint2 TileIndex = PixelPos >> TileShift;
//float Volume = 0;
uint BrickCount = 0;
#if 1
uint ListIndex = TileHead[ TileIndex ];
while( ListIndex )
{
FBrick Brick;
FRay LocalRay;
//do
{
FTileListElement Node = TileListBuffer[ ListIndex - 1 ];
ListIndex = Node.NextIndex;
uint BrickIndex = Node.BrickIndex;
#else
uint Offset = TileOffset[ TileIndex ];
uint Num = TileCount[ TileIndex ];
for( uint i = Offset; i < Offset + Num; i++ )
{
if( Ray.Time[1] < TileArrayBuffer[i].Depth )
break;
FBrick Brick;
FRay LocalRay;
{
uint BrickIndex = TileArrayBuffer[i].BrickIndex;
#endif
Brick = BrickBuffer[ BrickIndex ];
BrickCount++;
float3 BrickPos;
float CubeSize;
DecodeBrickKey( Brick.Key, BrickPos, CubeSize );
// Transform to local space
LocalRay = Ray;
LocalRay.Origin = Ray.Origin / CubeSize - BrickPos.xyz;
LocalRay.Direction = Ray.Direction / CubeSize;
if(1)
{
float3 Bounds[2] = { float3(0,0,0), float3(1,1,1) };
if(0)
{
uint2 RootBlock = BlockBuffer.Load2( 8 * Brick.BlockOffset );
uint3 Min, Max;
BlockBounds( RootBlock, Min, Max );
Bounds[0] = Min * 0.25;
Bounds[1] = Max * 0.25;
}
#if 0
else
{
uint3 Min, Max;
Min.x = BitFieldExtractU32( Node.Bounds, 2, 0 );
Min.y = BitFieldExtractU32( Node.Bounds, 2, 2 );
Min.z = BitFieldExtractU32( Node.Bounds, 2, 4 );
Max.x = BitFieldExtractU32( Node.Bounds, 2, 6 );
Max.y = BitFieldExtractU32( Node.Bounds, 2, 8 );
Max.z = BitFieldExtractU32( Node.Bounds, 2, 10 );
Max++;
Bounds[0] = Min * 0.25;
Bounds[1] = Max * 0.25;
}
#endif
LocalRay.Time = Intersect( LocalRay, Bounds );
if( LocalRay.Time[0] > LocalRay.Time[1] )
continue;
//float3 Extent = Bounds[1] - Bounds[0];
//Volume = Extent.x * Extent.y * Extent.z;
}
}
//while( LocalRay.Time[0] > LocalRay.Time[1] && ListIndex );
FRayCastCounters Counters = (FRayCastCounters)0;
#if VOXEL_NUM_LEVELS == 2
//float HitTime = RayCastBrick_L1( LocalRay, Brick.BlockOffset, Counters );
//float HitTime = RayCastBrick_L2( LocalRay, Brick.BlockOffset, Counters );
float HitTime = RayCastBrick_L2_WhileWhile( LocalRay, Brick.BlockOffset, Counters );
//float HitTime = RayCastBrick_L2_Flat( LocalRay, Brick.BlockOffset, Counters );
#else
float HitTime = RayCastBrick_L1( LocalRay, Brick.BlockOffset, Counters );
#endif
if( HitTime < LocalRay.Time[1] )
{
Ray.Time[1] = HitTime;
OutColor.r = Counters.Tests / 20.0;
OutColor.g = Counters.Steps / 20.0;
OutColor.g = Counters.StepIn / 10.0;
OutColor.b = Counters.StepOut / 10.0;
}
//BrickCount++;
}
//OutColor = ( TileHead[ TileIndex ] & 0xff ) / 255.0;
//OutColor.rgb = VisualizeCount( BrickCount );
//OutColor.rgb = BrickCount / 60.0;
OutColor = OutColor.r;
//OutColor = BrickCount / 6.0;
//OutColor.rgb = frac( Ray.Time[1] / 1000 );
OutSceneColor[ PixelPos + View.ViewRectMin.xy ] = OutColor;
}