|
|
|
|
|
|
#ifndef UNITY_SCREEN_SPACE_RAYMARCHING_INCLUDED |
|
|
|
#ifndef UNITY_SCREEN_SPACE_RAYMARCHING_INCLUDED |
|
|
|
struct ScreenSpaceRaymarchInput |
|
|
|
CBUFFER_START(ScreenSpaceRaymarching) |
|
|
|
int _SSRayMinLevel; |
|
|
|
int _SSRayMaxLevel; |
|
|
|
CBUFFER_END |
|
|
|
|
|
|
|
struct ScreenSpaceHiZRaymarchInput |
|
|
|
{ |
|
|
|
float3 startPositionVS; |
|
|
|
float startLinearDepth; |
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
bool writeStepDebug; |
|
|
|
uint2 sourcePositionSS; |
|
|
|
float sourceDepth; |
|
|
|
#endif |
|
|
|
}; |
|
|
|
|
|
|
|
struct ScreenSpaceLinearRaymarchInput |
|
|
|
{ |
|
|
|
float3 startPositionVS; |
|
|
|
float startLinearDepth; |
|
|
|
float3 dirVS; |
|
|
|
float4x4 projectionMatrix; |
|
|
|
int2 bufferSize; |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
bool writeStepDebug; |
|
|
|
#endif |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
float linearDepth; |
|
|
|
float2 positionSS; |
|
|
|
uint2 positionSS; |
|
|
|
float2 positionNDC; |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
float3 debugOutput; |
|
|
|
|
|
|
float _SSTCrossingOffset = 1; |
|
|
|
|
|
|
|
void CalculateRayTXS(ScreenSpaceRaymarchInput input, out float3 positionTXS, out float3 rayTXS) |
|
|
|
void CalculateRayTXS( |
|
|
|
float3 startPositionVS, |
|
|
|
float3 dirVS, |
|
|
|
float4x4 projectionMatrix, |
|
|
|
uint2 bufferSize, |
|
|
|
out float3 positionTXS, |
|
|
|
out float3 rayTXS) |
|
|
|
float3 positionVS = input.startPositionVS; |
|
|
|
float3 rayEndVS = input.startPositionVS + input.dirVS * 10; |
|
|
|
float3 positionVS = startPositionVS; |
|
|
|
float3 rayEndVS = startPositionVS + dirVS * 10; |
|
|
|
float4 positionCS = ComputeClipSpacePosition(positionVS, input.projectionMatrix); |
|
|
|
float4 rayEndCS = ComputeClipSpacePosition(rayEndVS, input.projectionMatrix); |
|
|
|
float4 positionCS = ComputeClipSpacePosition(positionVS, projectionMatrix); |
|
|
|
float4 rayEndCS = ComputeClipSpacePosition(rayEndVS, projectionMatrix); |
|
|
|
float2 positionNDC = ComputeNormalizedDeviceCoordinates(positionVS, input.projectionMatrix); |
|
|
|
float2 rayEndNDC = ComputeNormalizedDeviceCoordinates(rayEndVS, input.projectionMatrix); |
|
|
|
float2 positionNDC = ComputeNormalizedDeviceCoordinates(positionVS, projectionMatrix); |
|
|
|
float2 rayEndNDC = ComputeNormalizedDeviceCoordinates(rayEndVS, projectionMatrix); |
|
|
|
positionNDC.xy * input.bufferSize, |
|
|
|
positionNDC.xy * bufferSize, |
|
|
|
rayEndNDC.xy * input.bufferSize, |
|
|
|
rayEndNDC.xy * bufferSize, |
|
|
|
1.0 / rayEndCS.w); // Screen space depth interpolate properly in 1/z |
|
|
|
|
|
|
|
positionTXS = rayStartTXS; |
|
|
|
|
|
|
return rayDepth > invLinearDepth; |
|
|
|
} |
|
|
|
|
|
|
|
bool ScreenSpaceRaymarch( |
|
|
|
ScreenSpaceRaymarchInput input, |
|
|
|
float SampleHiZDepth(float2 positionTXS, int level) |
|
|
|
{ |
|
|
|
float pyramidDepth = LOAD_TEXTURE2D_LOD(_PyramidDepthTexture, int2(positionTXS.xy) >> level, level).r; |
|
|
|
float hiZLinearDepth = LinearEyeDepth(pyramidDepth, _ZBufferParams); |
|
|
|
float invHiZLinearDepth = 1 / hiZLinearDepth; |
|
|
|
return invHiZLinearDepth; |
|
|
|
} |
|
|
|
|
|
|
|
// positionTXS.z is 1/depth |
|
|
|
// rayTXS.z is 1/depth |
|
|
|
float3 IntersectDepthPlane(float3 positionTXS, float3 rayTXS, float invDepth, out float distance) |
|
|
|
{ |
|
|
|
const float EPSILON = 1E-5; |
|
|
|
|
|
|
|
// The depth of the intersection with the depth plane is: positionTXS.z + rayTXS.z * t = invDepth |
|
|
|
distance = (invDepth - positionTXS.z) / rayTXS.z; |
|
|
|
|
|
|
|
// (t<0) When the ray is going away from the depth plane, |
|
|
|
// put the intersection away. |
|
|
|
// Instead the intersection with the next tile will be used. |
|
|
|
// (t>=0) Add a small distance to go through the depth plane. |
|
|
|
distance = distance >= 0.0f ? (distance + EPSILON) : 1E5; |
|
|
|
|
|
|
|
// Return the point on the ray |
|
|
|
return positionTXS + rayTXS * distance; |
|
|
|
} |
|
|
|
|
|
|
|
bool CellAreEquals(int2 cellA, int2 cellB) |
|
|
|
{ |
|
|
|
return cellA.x == cellB.x && cellA.y == cellB.y; |
|
|
|
} |
|
|
|
|
|
|
|
float3 IntersectCellPlanes( |
|
|
|
float3 positionTXS, |
|
|
|
float3 rayTXS, |
|
|
|
float2 invRayTXS, |
|
|
|
int2 cellId, |
|
|
|
uint2 cellSize, |
|
|
|
int2 cellPlanes, |
|
|
|
float2 crossOffset, |
|
|
|
out float distance) |
|
|
|
{ |
|
|
|
// Planes to check |
|
|
|
int2 planes = (cellId + cellPlanes) * cellSize; |
|
|
|
// Hit distance to each planes |
|
|
|
float2 distanceToCellAxes = float2(planes - positionTXS.xy) * invRayTXS; // (distance to x axis, distance to y axis) |
|
|
|
distance = min(distanceToCellAxes.x, distanceToCellAxes.y); |
|
|
|
// Interpolate screen space to get next test point |
|
|
|
float3 testHitPositionTXS = positionTXS + rayTXS * distance; |
|
|
|
|
|
|
|
// Offset the proper axis to enforce cell crossing |
|
|
|
// https://gamedev.autodesk.com/blogs/1/post/5866685274515295601 |
|
|
|
testHitPositionTXS.xy += (distanceToCellAxes.x < distanceToCellAxes.y) |
|
|
|
? float2(crossOffset.x, 0) |
|
|
|
: float2(0, crossOffset.y); |
|
|
|
|
|
|
|
return testHitPositionTXS; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
void FillScreenSpaceRaymarchingHitDebug( |
|
|
|
uint2 bufferSize, |
|
|
|
float3 dirVS, |
|
|
|
float3 rayTXS, |
|
|
|
float3 startPositionTXS, |
|
|
|
bool hitSuccessful, |
|
|
|
int iteration, |
|
|
|
int maxIterations, |
|
|
|
int maxUsedLevel, |
|
|
|
int maxLevel, |
|
|
|
inout ScreenSpaceRayHit hit) |
|
|
|
{ |
|
|
|
float3 debugOutput = float3(0, 0, 0); |
|
|
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SCREEN_SPACE_TRACING_REFRACTION) |
|
|
|
{ |
|
|
|
switch (_DebugLightingSubMode) |
|
|
|
{ |
|
|
|
case DEBUGSCREENSPACETRACING_POSITION_NDC: |
|
|
|
debugOutput = float3(float2(startPositionTXS.xy) / bufferSize, 0); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_DIR_VS: |
|
|
|
debugOutput = dirVS * 0.5 + 0.5; |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_DIR_NDC: |
|
|
|
debugOutput = float3(rayTXS.xy * 0.5 + 0.5, frac(0.1 / rayTXS.z)); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_HIT_DISTANCE: |
|
|
|
debugOutput = frac(hit.distance * 0.1); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_HIT_DEPTH: |
|
|
|
debugOutput = frac(hit.linearDepth * 0.1); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_HIT_SUCCESS: |
|
|
|
debugOutput = hitSuccessful; |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_ITERATION_COUNT: |
|
|
|
debugOutput = float(iteration) / float(maxIterations); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_MAX_USED_LEVEL: |
|
|
|
debugOutput = float(maxUsedLevel) / float(maxLevel); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
hit.debugOutput = debugOutput; |
|
|
|
} |
|
|
|
|
|
|
|
void FillScreenSpaceRaymarchingPreLoopDebug( |
|
|
|
float3 startPositionTXS, |
|
|
|
inout ScreenSpaceTracingDebug debug) |
|
|
|
{ |
|
|
|
debug.startPositionSSX = uint(startPositionTXS.x); |
|
|
|
debug.startPositionSSY = uint(startPositionTXS.y); |
|
|
|
debug.startLinearDepth = 1 / startPositionTXS.z; |
|
|
|
} |
|
|
|
|
|
|
|
void FillScreenSpaceRaymarchingPostLoopDebug( |
|
|
|
int maxUsedLevel, |
|
|
|
int iteration, |
|
|
|
ScreenSpaceRayHit hit, |
|
|
|
inout ScreenSpaceTracingDebug debug) |
|
|
|
{ |
|
|
|
debug.levelMax = maxUsedLevel; |
|
|
|
debug.iterationMax = iteration; |
|
|
|
debug.hitDistance = hit.distance; |
|
|
|
} |
|
|
|
|
|
|
|
void FillScreenSpaceRaymarchingPreIterationDebug( |
|
|
|
int iteration, |
|
|
|
int currentLevel, |
|
|
|
inout ScreenSpaceTracingDebug debug) |
|
|
|
{ |
|
|
|
if (_DebugStep == iteration) |
|
|
|
debug.level = currentLevel; |
|
|
|
} |
|
|
|
|
|
|
|
void FillScreenSpaceRaymarchingPostIterationDebug( |
|
|
|
int iteration, |
|
|
|
uint2 cellSize, |
|
|
|
float3 positionTXS, |
|
|
|
float iterationDistance, |
|
|
|
float invHiZDepth, |
|
|
|
inout ScreenSpaceTracingDebug debug) |
|
|
|
{ |
|
|
|
if (_DebugStep == iteration) |
|
|
|
{ |
|
|
|
debug.cellSizeW = cellSize.x; |
|
|
|
debug.cellSizeH = cellSize.y; |
|
|
|
debug.positionTXS = positionTXS; |
|
|
|
debug.hitLinearDepth = 1 / positionTXS.z; |
|
|
|
debug.hitPositionSS = uint2(positionTXS.xy); |
|
|
|
debug.iteration = iteration; |
|
|
|
debug.iterationDistance = iterationDistance; |
|
|
|
debug.hiZLinearDepth = 1 / invHiZDepth; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
bool ScreenSpaceHiZRaymarch( |
|
|
|
ScreenSpaceHiZRaymarchInput input, |
|
|
|
// Initialize loop |
|
|
|
bool hitSuccessful = true; |
|
|
|
int iteration = 0; |
|
|
|
int minLevel = max(input.minLevel, _SSRayMinLevel); |
|
|
|
int maxLevel = min(input.maxLevel, _SSRayMaxLevel); |
|
|
|
// Caclulate TXS ray |
|
|
|
CalculateRayTXS(input, startPositionTXS, rayTXS); |
|
|
|
CalculateRayTXS( |
|
|
|
input.startPositionVS, |
|
|
|
input.dirVS, |
|
|
|
input.projectionMatrix, |
|
|
|
input.bufferSize, |
|
|
|
startPositionTXS, |
|
|
|
rayTXS); |
|
|
|
|
|
|
|
debug.startPositionSSX = uint(startPositionTXS.x); |
|
|
|
debug.startPositionSSY = uint(startPositionTXS.y); |
|
|
|
debug.startLinearDepth = 1 / startPositionTXS.z; |
|
|
|
FillScreenSpaceRaymarchingPreLoopDebug(startPositionTXS, debug); |
|
|
|
bool hitSuccessful = true; |
|
|
|
int iteration = 0; |
|
|
|
// No need to raymarch if the ray is along camera's foward |
|
|
|
if (!any(rayTXS.xy)) |
|
|
|
{ |
|
|
|
hit.distance = 1 / startPositionTXS.z; |
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
// Initialize raymarching |
|
|
|
float2 crossOffset = CROSS_OFFSET * cellPlanes * _SSTCrossingOffset; |
|
|
|
float2 crossOffset = CROSS_OFFSET * cellPlanes; |
|
|
|
// Initialize loop |
|
|
|
int currentLevel = input.minLevel; |
|
|
|
int currentLevel = minLevel; |
|
|
|
while (currentLevel >= input.minLevel) |
|
|
|
// Goes to the intersection with the first cell |
|
|
|
{ |
|
|
|
float2 absInvRayTXS = abs(invRayTXS); |
|
|
|
positionTXS += rayTXS * min(absInvRayTXS.x, absInvRayTXS.y); |
|
|
|
} |
|
|
|
|
|
|
|
while (currentLevel >= minLevel) |
|
|
|
{ |
|
|
|
if (iteration >= MAX_ITERATIONS) |
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
cellCount = input.bufferSize >> currentLevel; |
|
|
|
cellSize = uint2(1, 1) << currentLevel; |
|
|
|
|
|
|
|
if (_DebugStep == iteration) |
|
|
|
{ |
|
|
|
debug.cellSizeW = cellSize.x; |
|
|
|
debug.cellSizeH = cellSize.y; |
|
|
|
debug.positionTXS = positionTXS; |
|
|
|
debug.hitLinearDepth = 1 / positionTXS.z; |
|
|
|
debug.hitPositionSS = uint2(positionTXS.xy); |
|
|
|
debug.iteration = iteration; |
|
|
|
debug.level = currentLevel; |
|
|
|
} |
|
|
|
FillScreenSpaceRaymarchingPreIterationDebug(iteration, currentLevel, debug); |
|
|
|
// 1. Calculate hit in this HiZ cell |
|
|
|
int2 cellId = int2(positionTXS.xy) / cellSize; |
|
|
|
// Go down in HiZ levels by default |
|
|
|
int mipLevelDelta = -1; |
|
|
|
|
|
|
|
// Sampled as 1/Z so it interpolate properly in screen space. |
|
|
|
const float invHiZDepth = SampleHiZDepth(positionTXS.xy, currentLevel); |
|
|
|
float iterationDistance = 0; |
|
|
|
// Planes to check |
|
|
|
int2 planes = (cellId + cellPlanes) * cellSize; |
|
|
|
// Hit distance to each planes |
|
|
|
float2 distanceToCellAxes = float2(planes - positionTXS.xy) * invRayTXS; // (distance to x axis, distance to y axis) |
|
|
|
float distanceToCell = min(distanceToCellAxes.x, distanceToCellAxes.y); |
|
|
|
// Interpolate screen space to get next test point |
|
|
|
float3 testHitPositionTXS = positionTXS + rayTXS * distanceToCell; |
|
|
|
if (IsPositionAboveDepth(positionTXS.z, invHiZDepth)) |
|
|
|
{ |
|
|
|
float3 candidatePositionTXS = IntersectDepthPlane(positionTXS, rayTXS, invHiZDepth, iterationDistance); |
|
|
|
// Offset the proper axis to enforce cell crossing |
|
|
|
// https://gamedev.autodesk.com/blogs/1/post/5866685274515295601 |
|
|
|
testHitPositionTXS.xy += (distanceToCellAxes.x < distanceToCellAxes.y) |
|
|
|
? float2(crossOffset.x, 0) |
|
|
|
: float2(0, crossOffset.y); |
|
|
|
const int2 cellId = int2(positionTXS.xy) / cellSize; |
|
|
|
const int2 candidateCellId = int2(candidatePositionTXS.xy) / cellSize; |
|
|
|
// Check if we are out of the buffer |
|
|
|
if (any(testHitPositionTXS.xy > input.bufferSize) |
|
|
|
|| any(testHitPositionTXS.xy < 0)) |
|
|
|
{ |
|
|
|
hitSuccessful = false; |
|
|
|
break; |
|
|
|
// If we crossed the current cell |
|
|
|
if (!CellAreEquals(cellId, candidateCellId)) |
|
|
|
{ |
|
|
|
candidatePositionTXS = IntersectCellPlanes( |
|
|
|
positionTXS, |
|
|
|
rayTXS, |
|
|
|
invRayTXS, |
|
|
|
cellId, |
|
|
|
cellSize, |
|
|
|
cellPlanes, |
|
|
|
crossOffset, |
|
|
|
iterationDistance); |
|
|
|
|
|
|
|
// Go up a level to go faster |
|
|
|
mipLevelDelta = 1; |
|
|
|
} |
|
|
|
|
|
|
|
positionTXS = candidatePositionTXS; |
|
|
|
// 2. Sample the HiZ cell |
|
|
|
float pyramidDepth = LOAD_TEXTURE2D_LOD(_PyramidDepthTexture, int2(testHitPositionTXS.xy) >> currentLevel, currentLevel).r; |
|
|
|
float hiZLinearDepth = LinearEyeDepth(pyramidDepth, _ZBufferParams); |
|
|
|
float invHiZLinearDepth = 1 / hiZLinearDepth; |
|
|
|
hit.distance += iterationDistance; |
|
|
|
if (IsPositionAboveDepth(testHitPositionTXS.z, invHiZLinearDepth)) |
|
|
|
{ |
|
|
|
currentLevel = min(input.maxLevel, currentLevel + 1); |
|
|
|
currentLevel = min(currentLevel + mipLevelDelta, maxLevel); |
|
|
|
|
|
|
|
maxUsedLevel = max(maxUsedLevel, currentLevel); |
|
|
|
maxUsedLevel = max(maxUsedLevel, currentLevel); |
|
|
|
FillScreenSpaceRaymarchingPostIterationDebug( |
|
|
|
iteration, |
|
|
|
cellSize, |
|
|
|
positionTXS, |
|
|
|
iterationDistance, |
|
|
|
invHiZDepth, |
|
|
|
debug); |
|
|
|
positionTXS = testHitPositionTXS; |
|
|
|
hit.distance += distanceToCell; |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
|
// Check if we are out of the buffer |
|
|
|
if (any(positionTXS.xy > input.bufferSize) |
|
|
|
|| any(positionTXS.xy < 0)) |
|
|
|
float rayOffsetLength = (invHiZLinearDepth - positionTXS.z) / rayTXS.z; |
|
|
|
positionTXS += rayTXS * rayOffsetLength; |
|
|
|
hit.distance += rayOffsetLength; |
|
|
|
--currentLevel; |
|
|
|
hitSuccessful = false; |
|
|
|
break; |
|
|
|
cellCount = input.bufferSize >> currentLevel; |
|
|
|
cellSize = uint2(1, 1) << currentLevel; |
|
|
|
|
|
|
|
hit.positionSS = float2(positionTXS.xy) / float2(input.bufferSize); |
|
|
|
hit.positionNDC = float2(positionTXS.xy) / float2(input.bufferSize); |
|
|
|
hit.positionSS = uint2(positionTXS.xy); |
|
|
|
debug.levelMax = maxUsedLevel; |
|
|
|
debug.iterationMax = iteration; |
|
|
|
debug.hitDistance = hit.distance; |
|
|
|
FillScreenSpaceRaymarchingPostLoopDebug( |
|
|
|
maxUsedLevel, |
|
|
|
iteration, |
|
|
|
hit, |
|
|
|
debug); |
|
|
|
FillScreenSpaceRaymarchingHitDebug( |
|
|
|
input.bufferSize, input.dirVS, rayTXS, startPositionTXS, hitSuccessful, iteration, MAX_ITERATIONS, maxLevel, maxUsedLevel, |
|
|
|
hit); |
|
|
|
if (input.writeStepDebug) |
|
|
|
_DebugScreenSpaceTracingData[0] = debug; |
|
|
|
#endif |
|
|
|
|
|
|
|
return hitSuccessful; |
|
|
|
} |
|
|
|
|
|
|
|
// Based on DDA |
|
|
|
bool ScreenSpaceLinearRaymarch( |
|
|
|
ScreenSpaceLinearRaymarchInput input, |
|
|
|
out ScreenSpaceRayHit hit) |
|
|
|
{ |
|
|
|
const float2 CROSS_OFFSET = float2(1, 1); |
|
|
|
const int MAX_ITERATIONS = 1024; |
|
|
|
|
|
|
|
// Initialize loop |
|
|
|
ZERO_INITIALIZE(ScreenSpaceRayHit, hit); |
|
|
|
bool hitSuccessful = true; |
|
|
|
int iteration = 0; |
|
|
|
|
|
|
|
float3 startPositionTXS; |
|
|
|
float3 rayTXS; |
|
|
|
CalculateRayTXS( |
|
|
|
input.startPositionVS, |
|
|
|
input.dirVS, |
|
|
|
input.projectionMatrix, |
|
|
|
input.bufferSize, |
|
|
|
startPositionTXS, |
|
|
|
rayTXS); |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
ScreenSpaceTracingDebug debug; |
|
|
|
ZERO_INITIALIZE(ScreenSpaceTracingDebug, debug); |
|
|
|
FillScreenSpaceRaymarchingPreLoopDebug(startPositionTXS, debug); |
|
|
|
#endif |
|
|
|
if (input.writeStepDebug) |
|
|
|
// No need to raymarch if the ray is along camera's foward |
|
|
|
if (!any(rayTXS.xy)) |
|
|
|
_DebugScreenSpaceTracingData[0] = debug; |
|
|
|
hit.distance = 1 / startPositionTXS.z; |
|
|
|
hit.linearDepth = 1 / startPositionTXS.z; |
|
|
|
hit.positionSS = uint2(startPositionTXS.xy); |
|
|
|
|
|
|
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SCREEN_SPACE_TRACING_REFRACTION) |
|
|
|
else |
|
|
|
switch (_DebugLightingSubMode) |
|
|
|
if (abs(rayTXS.x) < abs(rayTXS.y)) |
|
|
|
// rayTXS.y is not null here |
|
|
|
rayTXS /= abs(rayTXS.y); |
|
|
|
else |
|
|
|
// rayTXS.x is not null here |
|
|
|
rayTXS /= abs(rayTXS.x); |
|
|
|
|
|
|
|
float3 positionTXS = startPositionTXS; |
|
|
|
while (iteration < MAX_ITERATIONS) |
|
|
|
case DEBUGSCREENSPACETRACING_POSITION_NDC: |
|
|
|
hit.debugOutput = float3(float2(startPositionTXS.xy) / input.bufferSize, 0); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_DIR_VS: |
|
|
|
hit.debugOutput = input.dirVS * 0.5 + 0.5; |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_DIR_NDC: |
|
|
|
hit.debugOutput = float3(rayTXS.xy * 0.5 + 0.5, frac(0.1 / rayTXS.z)); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_HIT_DISTANCE: |
|
|
|
hit.debugOutput = frac(hit.distance * 0.1); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_HIT_DEPTH: |
|
|
|
hit.debugOutput = frac(hit.linearDepth * 0.1); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_HIT_SUCCESS: |
|
|
|
hit.debugOutput = hitSuccessful; |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_ITERATION_COUNT: |
|
|
|
hit.debugOutput = float(iteration) / float(MAX_ITERATIONS); |
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
FillScreenSpaceRaymarchingPreIterationDebug(iteration, 0, debug); |
|
|
|
#endif |
|
|
|
|
|
|
|
positionTXS += rayTXS; |
|
|
|
float invHiZDepth = SampleHiZDepth(positionTXS.xy, 0); |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
FillScreenSpaceRaymarchingPostIterationDebug( |
|
|
|
iteration, |
|
|
|
uint2(0, 0), |
|
|
|
positionTXS, |
|
|
|
1 / rayTXS.z, |
|
|
|
invHiZDepth, |
|
|
|
debug); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (!IsPositionAboveDepth(positionTXS.z, invHiZDepth)) |
|
|
|
{ |
|
|
|
hitSuccessful = true; |
|
|
|
case DEBUGSCREENSPACETRACING_MAX_USED_LEVEL: |
|
|
|
hit.debugOutput = float(maxUsedLevel) / float(input.maxLevel); |
|
|
|
} |
|
|
|
|
|
|
|
// Check if we are out of the buffer |
|
|
|
if (any(positionTXS.xy > input.bufferSize) |
|
|
|
|| any(positionTXS.xy < 0)) |
|
|
|
{ |
|
|
|
hitSuccessful = false; |
|
|
|
} |
|
|
|
|
|
|
|
++iteration; |
|
|
|
|
|
|
|
hit.linearDepth = 1 / positionTXS.z; |
|
|
|
hit.positionNDC = float2(positionTXS.xy) / float2(input.bufferSize); |
|
|
|
hit.positionSS = uint2(positionTXS.xy); |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
FillScreenSpaceRaymarchingPostLoopDebug( |
|
|
|
0, |
|
|
|
iteration, |
|
|
|
hit, |
|
|
|
debug); |
|
|
|
FillScreenSpaceRaymarchingHitDebug( |
|
|
|
input.bufferSize, input.dirVS, rayTXS, startPositionTXS, hitSuccessful, iteration, MAX_ITERATIONS, 0, 0, |
|
|
|
hit); |
|
|
|
if (input.writeStepDebug) |
|
|
|
_DebugScreenSpaceTracingData[0] = debug; |
|
|
|
#endif |
|
|
|
|
|
|
|
return hitSuccessful; |
|
|
|