|
|
|
|
|
|
#ifndef UNITY_SCREEN_SPACE_RAYMARCHING_INCLUDED |
|
|
|
#define UNITY_SCREEN_SPACE_RAYMARCHING_INCLUDED |
|
|
|
|
|
|
|
struct ScreenSpaceRaymarchInput |
|
|
|
{ |
|
|
|
float3 startPositionVS; |
|
|
|
float startLinearDepth; |
|
|
|
float3 dirVS; |
|
|
|
float4x4 projectionMatrix; |
|
|
|
int2 bufferSize; |
|
|
|
int minLevel; |
|
|
|
int maxLevel; |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
uint2 initialStartPositionSS; |
|
|
|
float initialStartLinearDepth; |
|
|
|
#endif |
|
|
|
}; |
|
|
|
|
|
|
|
struct ScreenSpaceRayHit |
|
|
|
{ |
|
|
|
float distance; |
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
bool ScreenSpaceRaymarch( |
|
|
|
float3 startPositionVS, |
|
|
|
float startLinearDepth, |
|
|
|
float3 dirVS, |
|
|
|
float4x4 projectionMatrix, |
|
|
|
int2 bufferSize, |
|
|
|
int minLevel, |
|
|
|
int maxLevel, |
|
|
|
ScreenSpaceRaymarchInput input, |
|
|
|
out ScreenSpaceRayHit hit) |
|
|
|
{ |
|
|
|
// dirVS must be normalized |
|
|
|
|
|
|
|
|
|
|
float4 startPositionCS = mul(projectionMatrix, float4(startPositionVS, 1)); |
|
|
|
float4 dirCS = mul(projectionMatrix, float4(dirVS, 1)); |
|
|
|
float4 startPositionCS = mul(input.projectionMatrix, float4(input.startPositionVS, 1)); |
|
|
|
float4 dirCS = mul(input.projectionMatrix, float4(input.dirVS, 1)); |
|
|
|
#if UNITY_UV_STARTS_AT_TOP |
|
|
|
// Our clip space is correct, but the NDC is flipped. |
|
|
|
// Conceptually, it should be (positionNDC.y = 1.0 - positionNDC.y), but this is more efficient. |
|
|
|
|
|
|
float2 invDirNDC = 1 / dirNDC.xy; |
|
|
|
int2 cellPlanes = clamp(sign(dirNDC.xy), 0, 1); |
|
|
|
|
|
|
|
int2 startPositionTXS = int2(startPositionNDC * bufferSize); |
|
|
|
int2 startPositionTXS = int2(startPositionNDC * input.bufferSize); |
|
|
|
int currentLevel = minLevel; |
|
|
|
int2 cellCount = bufferSize >> currentLevel; |
|
|
|
int2 cellSize = int2(1 / float2(cellCount)); |
|
|
|
int currentLevel = input.minLevel; |
|
|
|
int2 cellCount = input.bufferSize >> currentLevel; |
|
|
|
uint2 cellSize = uint2(1, 1) << currentLevel; |
|
|
|
float3 positionTXS = float3(float2(startPositionTXS), startLinearDepth); |
|
|
|
float3 positionTXS = float3(float2(startPositionTXS), input.startLinearDepth); |
|
|
|
int iteration = 0; |
|
|
|
|
|
|
|
bool hitSuccessful = true; |
|
|
|
|
|
|
uint2 debugCellSize = cellSize; |
|
|
|
while (currentLevel >= minLevel) |
|
|
|
while (currentLevel >= input.minLevel) |
|
|
|
if (++iteration < MAX_ITERATIONS) |
|
|
|
if (iteration < MAX_ITERATIONS) |
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
if (_DebugStep == iteration) |
|
|
|
{ |
|
|
|
debugCellSize = cellSize; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// 1. Calculate hit in this HiZ cell |
|
|
|
int2 cellId = int2(positionTXS.xy) / cellCount; |
|
|
|
|
|
|
|
|
|
|
// https://gamedev.autodesk.com/blogs/1/post/5866685274515295601 |
|
|
|
testHitPositionTXS.xy += (planeHits.x < planeHits.y) ? float2(CROSS_OFFSET.x, 0) : float2(0, CROSS_OFFSET.y); |
|
|
|
|
|
|
|
if (any(testHitPositionTXS.xy > bufferSize) |
|
|
|
if (any(testHitPositionTXS.xy > input.bufferSize) |
|
|
|
|| any(testHitPositionTXS.xy < 0)) |
|
|
|
{ |
|
|
|
hitSuccessful = false; |
|
|
|
|
|
|
|
|
|
|
if (hiZLinearDepth > testHitPositionTXS.z) |
|
|
|
{ |
|
|
|
currentLevel = min(maxLevel, currentLevel + 1); |
|
|
|
currentLevel = min(input.maxLevel, currentLevel + 1); |
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
maxUsedLevel = max(maxUsedLevel, currentLevel); |
|
|
|
#endif |
|
|
|
|
|
|
--currentLevel; |
|
|
|
} |
|
|
|
|
|
|
|
cellCount = bufferSize >> currentLevel; |
|
|
|
cellSize = int2(1 / float2(cellCount)); |
|
|
|
cellCount = input.bufferSize >> currentLevel; |
|
|
|
cellSize = uint2(1, 1) << currentLevel; |
|
|
|
|
|
|
|
++iteration; |
|
|
|
hit.positionSS = float2(positionTXS.xy) / float2(bufferSize); |
|
|
|
hit.positionSS = float2(positionTXS.xy) / float2(input.bufferSize); |
|
|
|
|
|
|
|
#ifdef DEBUG_DISPLAY |
|
|
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SCREEN_SPACE_TRACING_REFRACTION) |
|
|
|
|
|
|
hit.debugOutput = float3(startPositionNDC.xy, 0); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_DIR_VS: |
|
|
|
hit.debugOutput = dirVS * 0.5 + 0.5; |
|
|
|
hit.debugOutput = input.dirVS * 0.5 + 0.5; |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_DIR_NDC: |
|
|
|
hit.debugOutput = float3(dirNDC.xy * 0.5 + 0.5, dirNDC.z); |
|
|
|
|
|
|
hit.debugOutput = float(iteration) / float(MAX_ITERATIONS); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_MAX_USED_LEVEL: |
|
|
|
hit.debugOutput = float(maxUsedLevel) / float(maxLevel); |
|
|
|
hit.debugOutput = float(maxUsedLevel) / float(input.maxLevel); |
|
|
|
break; |
|
|
|
case DEBUGSCREENSPACETRACING_STEP_BY_STEP: |
|
|
|
{ |
|
|
|
float2 distanceToCell = abs(float2(input.initialStartPositionSS % debugCellSize) - float2(debugCellSize) / float2(2, 2)); |
|
|
|
distanceToCell = clamp(1 - distanceToCell, 0, 1); |
|
|
|
float cellSDF = max(distanceToCell.x, distanceToCell.y); |
|
|
|
float3 gridColor = float3( |
|
|
|
frac(input.initialStartLinearDepth * 0.1).xx, |
|
|
|
cellSDF); |
|
|
|
hit.debugOutput = gridColor; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|