Add additional HitNormal feature to Global SDF trace output

This commit is contained in:
Wojciech Figat
2022-03-29 15:02:27 +02:00
parent 9d56093381
commit 787e7b423c

View File

@@ -24,6 +24,7 @@ struct GlobalSDFTrace
float3 WorldDirection;
float MaxDistance;
float StepScale;
bool NeedsHitNormal;
void Init(float3 worldPosition, float3 worldDirection, float minDistance, float maxDistance, float stepScale = 1.0f)
{
@@ -32,12 +33,14 @@ struct GlobalSDFTrace
MinDistance = minDistance;
MaxDistance = maxDistance;
StepScale = stepScale;
NeedsHitNormal = false;
}
};
// Global SDF ray trace hit information.
struct GlobalSDFHit
{
float3 HitNormal;
float HitTime;
uint HitCascade;
uint StepsCount;
@@ -54,13 +57,13 @@ struct GlobalSDFHit
};
// Samples the Global SDF and returns the distance to the closest surface (in world units) at the given world location.
float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition, uint minCascade = 0)
float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition)
{
float distance = data.CascadePosDistance[3].w * 2.0f;
if (distance <= 0.0f)
return 60000;
UNROLL
for (uint cascade = minCascade; cascade < 4; cascade++)
for (uint cascade = 0; cascade < 4; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float cascadeMaxDistance = cascadePosDistance.w * 2;
@@ -77,14 +80,14 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3
}
// Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector.
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition, out float distance, uint minCascade = 0)
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition, out float distance)
{
float3 gradient = float3(0, 0.00001f, 0);
distance = 60000;
if (data.CascadePosDistance[3].w <= 0.0f)
return gradient;
UNROLL
for (uint cascade = minCascade; cascade < 4; cascade++)
for (uint cascade = 0; cascade < 4; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float cascadeMaxDistance = cascadePosDistance.w * 2;
@@ -109,19 +112,17 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4]
}
// Ray traces the Global SDF.
GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], Texture3D<float> mips[4], const GlobalSDFTrace trace, uint minCascade = 0)
GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], Texture3D<float> mips[4], const GlobalSDFTrace trace)
{
GlobalSDFHit hit;
GlobalSDFHit hit = (GlobalSDFHit)0;
hit.HitTime = -1.0f;
hit.HitCascade = 0;
hit.StepsCount = 0;
float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1)
float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1)
float nextIntersectionStart = 0.0f;
float traceMaxDistance = min(trace.MaxDistance, data.CascadePosDistance[3].w * 2);
float3 traceEndPosition = trace.WorldPosition + trace.WorldDirection * traceMaxDistance;
UNROLL
for (uint cascade = minCascade; cascade < 4 && hit.HitTime < 0.0f; cascade++)
for (uint cascade = 0; cascade < 4 && hit.HitTime < 0.0f; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float cascadeMaxDistance = cascadePosDistance.w * 2;
@@ -173,6 +174,18 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4]
// Surface hit
hit.HitTime = max(stepTime + stepDistance - minSurfaceThickness, 0.0f);
hit.HitCascade = cascade;
if (trace.NeedsHitNormal)
{
// Calculate hit normal from SDF gradient
float texelOffset = 1.0f / data.Resolution;
float xp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x + texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float xn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x - texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float yp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y + texelOffset, cascadeUV.z), 0).x;
float yn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y - texelOffset, cascadeUV.z), 0).x;
float zp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z + texelOffset), 0).x;
float zn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z - texelOffset), 0).x;
hit.HitNormal = normalize(float3(xp - xn, yp - yn, zp - zn));
}
break;
}