// Copyright Epic Games, Inc. All Rights Reserved. #include "../../Common.ush" #include "Brick.ush" #include "Voxel.ush" // *** The following SV_DepthLessEqual support is based on MaterialTemplate.ush implementation: *** // Whether to use the hidden d3d11 feature that supports depth writes with ZCull by only pushing into the screen //@todo - use for other SM5 platforms #define SUPPORTS_CONSERVATIVE_DEPTH_WRITES ((COMPILER_HLSL && FEATURE_LEVEL >= FEATURE_LEVEL_SM5) || COMPILER_PSSL || (COMPILER_METAL && FEATURE_LEVEL >= FEATURE_LEVEL_SM5) || SWITCH_PROFILE || SWITCH_PROFILE_FORWARD) #if SUPPORTS_CONSERVATIVE_DEPTH_WRITES #if COMPILER_HLSL || COMPILER_METAL_SHADER_CONVERTER || COMPILER_METAL || SWITCH_PROFILE || SWITCH_PROFILE_FORWARD #define DEPTH_LE_OUTPUT SV_DepthLessEqual #elif COMPILER_PSSL #define DEPTH_LE_OUTPUT S_DEPTH_LE_OUTPUT #else #error SUPPORTS_CONSERVATIVE_DEPTH_WRITES enabled for unsupported platform #endif #else #define DEPTH_LE_OUTPUT SV_DEPTH #endif void DrawBricksVS( uint VertexID : SV_VertexID, uint InstanceID : SV_InstanceID, out uint OutBrickOffset : TEXCOORD0, out uint OutBounds : TEXCOORD1, out float3 RayOrigin : TEXCOORD2, out float3 RayDirection : TEXCOORD3, out float4 OutPosition : SV_POSITION ) { uint LocalBrickID = VertexID / VertsPerBrick; InstanceID = InstanceID * BricksPerInstance + LocalBrickID; VertexID = VertexID - LocalBrickID * VertsPerBrick; uint NumBricks = GetNumBricks(); BRANCH if( InstanceID >= NumBricks ) { OutPosition = float4(0,0,0,1); OutBrickOffset = 0u; OutBounds = 0u; RayOrigin = 0; RayDirection = 0; return; } FBrick Brick = BrickBuffer[ InstanceID ]; float3 BrickPos; float CubeSize; DecodeBrickKey( Brick.Key, BrickPos, CubeSize ); float3 WorldMin = BrickPos * CubeSize; float3 WorldMax = WorldMin + CubeSize; if(1) { 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; BrickMax++; OutBounds = BrickBounds; 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; } OutBrickOffset = Brick.BlockOffset; #if DRAW_RECTS 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 ); } #if PLATFORM_SUPPORTS_RECT_LIST OutPosition.x = VertexID == 1 ? RectMax.x : RectMin.x; OutPosition.y = VertexID == 2 ? RectMax.y : RectMin.y; OutPosition.z = RectMax.z; OutPosition.w = 1; #else OutPosition.x = VertexID & 1 ? RectMax.x : RectMin.x; OutPosition.y = VertexID & 2 ? RectMax.y : RectMin.y; OutPosition.z = RectMax.z; OutPosition.w = 1; #endif #else bool3 Corner; Corner.z = ( VertexID >> 0 ) & 1; Corner.y = ( VertexID >> 1 ) & 1; Corner.x = ( VertexID >> 2 ) & 1; float3 Position = Corner ? WorldMax : WorldMin; OutPosition = mul( float4( Position, 1 ), View.TranslatedWorldToClip ); #endif FRay Ray; Ray.Origin = View.TranslatedWorldCameraOrigin; Ray.Direction = mul( float4( OutPosition.xy, 0, 1 ), View.ClipToTranslatedWorld ).xyz; // Transform to local space RayOrigin = Ray.Origin / CubeSize - BrickPos; RayDirection = Ray.Direction / CubeSize; //OutPosition.z = 1.0 - InstanceID / 1000000.0; } ENABLE_RE_Z void DrawBricksPS( in nointerpolation uint BrickOffset : TEXCOORD0, in nointerpolation uint BrickBounds : TEXCOORD1, in noperspective float3 RayOrigin : TEXCOORD2, in noperspective float3 RayDirection : TEXCOORD3, in centroid float4 SvPosition : SV_Position, out float4 OutColor : SV_Target0, out float OutDepth : DEPTH_LE_OUTPUT ) { FRay Ray; Ray.Origin = RayOrigin; Ray.Direction = RayDirection; Ray.Time[0] = 0; Ray.Time[1] = 1e24; const float Epsilon = 1e-8; float3 Replacement = select( Ray.Direction > 0, Epsilon, -Epsilon ); Ray.Direction = select( abs( Ray.Direction ) < Epsilon, Replacement, Ray.Direction ); #if 0 OutColor = 0.1; #elif 0 float3 BrickPos = CubePos.xyz; float CubeSize = rcp(CubePos.w); //float CubeSize = CubePos.w; float3 WorldMin = BrickPos * CubeSize; float3 WorldMax = WorldMin + CubeSize; float3 Bounds[2] = { WorldMin, WorldMax }; // Ray intersect with box float3 InvDir = rcp( Ray.Direction ); float3 PlaneIntersect0 = ( Bounds[0] - Ray.Origin ) * InvDir; float3 PlaneIntersect1 = ( Bounds[1] - Ray.Origin ) * InvDir; float3 MinIntersection = min( PlaneIntersect0, PlaneIntersect1 ); float3 MaxIntersection = max( PlaneIntersect0, PlaneIntersect1 ); Ray.Time[0] = max( Ray.Time[0], max3( MinIntersection.x, MinIntersection.y, MinIntersection.z ) ); Ray.Time[1] = min( Ray.Time[1], min3( MaxIntersection.x, MaxIntersection.y, MaxIntersection.z ) ); OutColor = Ray.Time[0] <= Ray.Time[1] ? 0.1 : 0; if( Ray.Time[0] > Ray.Time[1] ) discard; #elif 0 float3 Bounds[2] = { float3(0,0,0), float3(1,1,1) }; // Ray intersect with box float3 InvDir = rcp( Ray.Direction ); float3 PlaneIntersect0 = ( Bounds[0] - Ray.Origin ) * InvDir; float3 PlaneIntersect1 = ( Bounds[1] - Ray.Origin ) * InvDir; float3 MinIntersection = min( PlaneIntersect0, PlaneIntersect1 ); float3 MaxIntersection = max( PlaneIntersect0, PlaneIntersect1 ); Ray.Time[0] = max( Ray.Time[0], max3( MinIntersection.x, MinIntersection.y, MinIntersection.z ) ); Ray.Time[1] = min( Ray.Time[1], min3( MaxIntersection.x, MaxIntersection.y, MaxIntersection.z ) ); OutColor = Ray.Time[0] <= Ray.Time[1] ? 0.1 : 0; if( Ray.Time[0] > Ray.Time[1] ) discard; #else float3 Bounds[2] = { float3(0,0,0), float3(1,1,1) }; { uint3 Min, Max; Min.x = BitFieldExtractU32( BrickBounds, 2, 0 ); Min.y = BitFieldExtractU32( BrickBounds, 2, 2 ); Min.z = BitFieldExtractU32( BrickBounds, 2, 4 ); Max.x = BitFieldExtractU32( BrickBounds, 2, 6 ); Max.y = BitFieldExtractU32( BrickBounds, 2, 8 ); Max.z = BitFieldExtractU32( BrickBounds, 2, 10 ); Max++; Bounds[0] = Min * 0.25; Bounds[1] = Max * 0.25; } Ray.Time = Intersect( Ray, Bounds ); FRayCastCounters Counters = (FRayCastCounters)0; if( Ray.Time[0] < Ray.Time[1] ) { #if VOXEL_NUM_LEVELS == 2 //Ray.Time[0] = RayCastBrick_L1( Ray, BrickOffset, Counters ); //Ray.Time[0] = RayCastBrick_L2( Ray, BrickOffset, Counters ); Ray.Time[0] = RayCastBrick_L2_WhileWhile( Ray, BrickOffset, Counters ); //Ray.Time[0] = RayCastBrick_L2_Flat( Ray, BrickOffset, Counters ); #else Ray.Time[0] = RayCastBrick_L1( Ray, BrickOffset, Counters ); #endif OutColor.r = Counters.Tests / 20.0; OutColor.g = Counters.Steps / 20.0; OutColor.g = Counters.StepIn / 10.0; OutColor.b = Counters.StepOut / 10.0; OutColor = OutColor.r; //OutColor.rgb = VisualizeCount( Counters.StepOut ); //OutColor.rgb = frac( Ray.Time[1] / 1000 ); } OutDepth = View.ViewToClip[3][2] / Ray.Time[0] + View.ViewToClip[2][2]; if( Ray.Time[0] >= Ray.Time[1] ) discard; #endif }