浏览代码

Update screen space tracing for refractions

/feature-ScreenSpaceProjection
Frédéric Vauchelles 7 年前
当前提交
fb9b45ba
共有 5 个文件被更改,包括 194 次插入106 次删除
  1. 24
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Debug.hlsl
  2. 216
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/ScreenSpaceRaymarching.hlsl
  3. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.cs
  4. 15
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.cs.hlsl
  5. 41
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugFullScreen.shader

24
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Debug.hlsl


bool SampleDebugFontNumber(int2 pixCoord, uint number)
{
pixCoord.y -= 4;
if (number <= 9)
{
return SampleDebugFont(pixCoord - int2(6, 0), number);
}
else
{
return (SampleDebugFont(pixCoord, number / 10) | SampleDebugFont(pixCoord - int2(6, 0), number % 10));
}
// Maximum 10 digits
for (int i = 10; i >= 0; ++i)
{
uint toTest = number % 10;
if (SampleDebugFont(pixCoord, toTest))
return true;
if (number <= 9)
return false;
number = number / 10;
pixCoord += int2(6, 0);
}
return false;
}
float4 GetStreamingMipColor(uint mipCount, float4 mipInfo)

216
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/ScreenSpaceRaymarching.hlsl


#endif
};
bool ScreenSpaceRaymarch(
ScreenSpaceRaymarchInput input,
out ScreenSpaceRayHit hit)
void CalculateRayTXS(ScreenSpaceRaymarchInput input, out float3 positionTXS, out float3 rayTXS)
// dirVS must be normalized
float3 positionVS = input.startPositionVS;
float3 rayEndVS = input.startPositionVS + input.dirVS * 10;
const float2 CROSS_OFFSET = float2(2, 2);
const int MAX_ITERATIONS = 32;
float4 positionCS = ComputeClipSpacePosition(positionVS, input.projectionMatrix);
float4 rayEndCS = ComputeClipSpacePosition(rayEndVS, input.projectionMatrix);
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.
startPositionCS.y = -startPositionCS.y;
dirCS.y = -dirCS.y;
#endif
float2 positionNDC = ComputeNormalizedDeviceCoordinates(positionVS, input.projectionMatrix);
float2 rayEndNDC = ComputeNormalizedDeviceCoordinates(rayEndVS, input.projectionMatrix);
float2 startPositionNDC = (startPositionCS.xy * rcp(startPositionCS.w)) * 0.5 + 0.5;
// store linear depth in z
float l = length(dirCS.xy);
float3 dirNDC = dirCS.xyz / l;
float3 rayStartTXS = float3(
positionNDC.xy * input.bufferSize,
1.0 / positionCS.w); // Screen space depth interpolate properly in 1/z
float2 invDirNDC = float2(1, 1) / dirNDC.xy;
int2 cellPlanes = sign(dirNDC.xy);
float2 crossOffset = CROSS_OFFSET * cellPlanes;
cellPlanes = clamp(cellPlanes, 0, 1);
float3 rayEndTXS = float3(
rayEndNDC.xy * input.bufferSize,
1.0 / rayEndCS.w); // Screen space depth interpolate properly in 1/z
uint2 startPositionTXS = uint2(startPositionNDC * input.bufferSize);
positionTXS = rayStartTXS;
rayTXS = rayEndTXS - rayStartTXS;
}
ZERO_INITIALIZE(ScreenSpaceRayHit, hit);
bool IsPositionAboveDepth(float rayDepth, float invLinearDepth)
{
// as depth is inverted, we must invert the check as well
// rayZ > HiZ <=> 1/rayZ < 1/HiZ
return rayDepth > invLinearDepth;
}
int currentLevel = input.minLevel;
uint2 cellCount = input.bufferSize >> currentLevel;
uint2 cellSize = uint2(1, 1) << currentLevel;
bool ScreenSpaceRaymarch(
ScreenSpaceRaymarchInput input,
out ScreenSpaceRayHit hit)
{
const float2 CROSS_OFFSET = float2(2, 2);
const int MAX_ITERATIONS = 32;
// store linear depth in z
float3 positionTXS = float3(float2(startPositionTXS), input.startLinearDepth);
int iteration = 0;
ZERO_INITIALIZE(ScreenSpaceRayHit, hit);
bool hitSuccessful = true;
// Caclulate TXS ray
float3 startPositionTXS;
float3 rayTXS;
CalculateRayTXS(input, startPositionTXS, rayTXS);
int maxUsedLevel = currentLevel;
int maxUsedLevel = input.minLevel;
debug.startPositionSSX = startPositionTXS.x;
debug.startPositionSSY = startPositionTXS.y;
debug.startLinearDepth = input.startLinearDepth;
debug.startPositionSSX = uint(startPositionTXS.x);
debug.startPositionSSY = uint(startPositionTXS.y);
debug.startLinearDepth = 1 / startPositionTXS.z;
while (currentLevel >= input.minLevel)
bool hitSuccessful = true;
int iteration = 0;
if (!any(rayTXS.xy))
if (iteration >= MAX_ITERATIONS)
hit.distance = 1 / startPositionTXS.z;
hit.linearDepth = 1 / startPositionTXS.z;
hit.positionSS = uint2(startPositionTXS.xy);
}
else
{
float2 invRayTXS = float2(1, 1) / rayTXS.xy;
// Calculate planes to intersect for each cell
int2 cellPlanes = sign(rayTXS.xy);
float2 crossOffset = CROSS_OFFSET * cellPlanes;
cellPlanes = clamp(cellPlanes, 0, 1);
// Initialize loop
int currentLevel = input.minLevel;
uint2 cellCount = input.bufferSize >> currentLevel;
uint2 cellSize = uint2(1, 1) << currentLevel;
float3 positionTXS = startPositionTXS;
while (currentLevel >= input.minLevel)
hitSuccessful = false;
break;
}
if (iteration >= MAX_ITERATIONS)
{
hitSuccessful = false;
break;
}
if (_DebugStep == iteration)
{
debug.cellSizeW = cellSize.x;
debug.cellSizeH = cellSize.y;
debug.positionTXS = positionTXS;
}
if (_DebugStep == iteration)
{
debug.cellSizeW = cellSize.x;
debug.cellSizeH = cellSize.y;
debug.positionTXS = positionTXS;
debug.hitLinearDepth = 1 / positionTXS.z;
debug.hitPositionSS = uint2(positionTXS.xy);
}
// 1. Calculate hit in this HiZ cell
int2 cellId = int2(positionTXS.xy) / cellCount;
// 1. Calculate hit in this HiZ cell
int2 cellId = int2(positionTXS.xy) / cellSize;
// Planes to check
int2 planes = (cellId + cellPlanes) * cellSize;
// Hit distance to each planes
float2 distanceToCellAxes = float2(planes - positionTXS.xy) * invDirNDC; // (distance to x axis, distance to y axis)
float distanceToCell = min(distanceToCellAxes.x, distanceToCellAxes.y);
float3 testHitPositionTXS = positionTXS + dirNDC * distanceToCell;
// 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;
// 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);
// 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);
if (any(testHitPositionTXS.xy > input.bufferSize)
|| any(testHitPositionTXS.xy < 0))
{
hitSuccessful = false;
break;
}
// Check if we are out of the buffer
if (any(testHitPositionTXS.xy > input.bufferSize)
|| any(testHitPositionTXS.xy < 0))
{
hitSuccessful = false;
break;
}
// 2. Sample the HiZ cell
float pyramidDepth = LOAD_TEXTURE2D_LOD(_PyramidDepthTexture, int2(testHitPositionTXS.xy) >> currentLevel, currentLevel).r;
float hiZLinearDepth = LinearEyeDepth(pyramidDepth, _ZBufferParams);
// 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;
if (hiZLinearDepth < testHitPositionTXS.z)
{
currentLevel = min(input.maxLevel, currentLevel + 1);
if (IsPositionAboveDepth(testHitPositionTXS.z, invHiZLinearDepth))
{
currentLevel = min(input.maxLevel, currentLevel + 1);
maxUsedLevel = max(maxUsedLevel, currentLevel);
maxUsedLevel = max(maxUsedLevel, currentLevel);
positionTXS = testHitPositionTXS;
hit.distance += distanceToCell;
}
else
{
float rayOffsetLength = (hiZLinearDepth - positionTXS.z) / dirNDC.z;
positionTXS += dirNDC * rayOffsetLength;
hit.distance += rayOffsetLength;
--currentLevel;
}
cellCount = input.bufferSize >> currentLevel;
cellSize = uint2(1, 1) << currentLevel;
positionTXS = testHitPositionTXS;
hit.distance += distanceToCell;
}
else
{
float rayOffsetLength = (invHiZLinearDepth - positionTXS.z) / rayTXS.z;
positionTXS += rayTXS * rayOffsetLength;
hit.distance += rayOffsetLength;
--currentLevel;
}
++iteration;
}
cellCount = input.bufferSize >> currentLevel;
cellSize = uint2(1, 1) << currentLevel;
hit.linearDepth = positionTXS.z;
hit.positionSS = float2(positionTXS.xy) / float2(input.bufferSize);
++iteration;
}
hit.linearDepth = 1 / positionTXS.z;
hit.positionSS = float2(positionTXS.xy) / float2(input.bufferSize);
}
debug.hitDistance = hit.distance;
if (input.writeStepDebug)
{

switch (_DebugLightingSubMode)
{
case DEBUGSCREENSPACETRACING_POSITION_NDC:
hit.debugOutput = float3(startPositionNDC.xy, 0);
hit.debugOutput = float3(float2(startPositionTXS.xy) / input.bufferSize, 0);
hit.debugOutput = float3(dirNDC.xy * 0.5 + 0.5, dirNDC.z);
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);

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.cs


public uint iteration;
public uint iterationMax;
public float hitDistance;
public float hitLinearDepth;
public Vector2 hitPositionSS;
public override string ToString()
{
return string.Format(

15
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.cs.hlsl


uint levelMax;
uint iteration;
uint iterationMax;
float hitDistance;
float hitLinearDepth;
float2 hitPositionSS;
};
//

uint GetIterationMax(ScreenSpaceTracingDebug value)
{
return value.iterationMax;
}
float GetHitDistance(ScreenSpaceTracingDebug value)
{
return value.hitDistance;
}
float GetHitLinearDepth(ScreenSpaceTracingDebug value)
{
return value.hitLinearDepth;
}
float2 GetHitPositionSS(ScreenSpaceTracingDebug value)
{
return value.hitPositionSS;
}

41
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugFullScreen.shader


#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/ShaderLibrary/Color.hlsl"
#include "CoreRP/ShaderLibrary/Debug.hlsl"
#include "../ShaderVariables.hlsl"
#include "../Debug/DebugDisplay.cs.hlsl"

}
if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_SCREEN_SPACE_TRACING_REFRACTION)
{
const float circleRadius = 3.5;
const float ringSize = 1.5;
float4 color = SAMPLE_TEXTURE2D(_DebugFullScreenTexture, s_point_clamp_sampler, input.texcoord);
uint4 v01 = LOAD_TEXTURE2D(_DebugScreenSpaceTracing, uint2(0, 0));

uint2 cellSize = uint2(debug.cellSizeW, debug.cellSizeH);
float2 distanceToCell = abs(float2(posInput.positionSS % cellSize) - float2(cellSize) / float2(2, 2));
// Grid rendering
float2 distanceToCell = float2(posInput.positionSS % cellSize);
distanceToCell = min(distanceToCell, float2(cellSize) - distanceToCell);
// Position dot rendering
float positionSDF = clamp(4 - distanceToPosition, 0, 1);
float positionSDF = clamp(circleRadius - distanceToPosition, 0, 1);
// Start position dot rendering
float startPositionSDF = clamp(4 - distanceToStartPosition, 0, 1);
float startPositionSDF = clamp(circleRadius - distanceToStartPosition, 0, 1);
// Aggregated sdf colors
return float4(debugColor * 0.5 + color.rgb * 0.5, 1);
// Combine debug color with background (with opacity)
float4 col = float4(debugColor * 0.5 + color.rgb * 0.5, 1);
// Calculate SDF to draw a ring on both dots
float startPositionRingDistance = abs(distanceToStartPosition - circleRadius);
float startPositionRingSDF = clamp(ringSize - startPositionRingDistance, 0, 1);
float positionRingDistance = abs(distanceToPosition - circleRadius);
float positionRingSDF = clamp(ringSize - positionRingDistance, 0, 1);
float w = clamp(1 - startPositionRingSDF - positionRingSDF, 0, 1);
col = col * w + float4(1, 1, 1, 1) * (1 - w);
if (posInput.positionSS.y < 200)
{
// Draw debug statistics
uint depth = uint(debug.startLinearDepth * 1000);
if (SampleDebugFontNumber(posInput.positionSS - uint2(100, 10), depth))
col = float4(1, 1, 1, 1);
uint hitLinearDepth = uint(debug.hitLinearDepth * 1000);
if (SampleDebugFontNumber(posInput.positionSS - uint2(100, 30), hitLinearDepth))
col = float4(1, 1, 1, 1);
}
return col;
}
return float4(0.0, 0.0, 0.0, 0.0);

正在加载...
取消
保存