310 lines
7.5 KiB
HLSL
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;
|
|
} |