From 6c4e61a924df2053b6eccb37661f5db867e9f388 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Fri, 25 Mar 2022 12:53:30 +0100 Subject: [PATCH] Add `SampleGlobalSDFGradient` to get normal vector of Global SDF --- Content/Shaders/GlobalSignDistanceField.flax | 4 +-- Source/Shaders/GlobalSignDistanceField.hlsl | 31 +++++++++++++++++++ Source/Shaders/GlobalSignDistanceField.shader | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Content/Shaders/GlobalSignDistanceField.flax b/Content/Shaders/GlobalSignDistanceField.flax index 88e8ebcc6..671925ceb 100644 --- a/Content/Shaders/GlobalSignDistanceField.flax +++ b/Content/Shaders/GlobalSignDistanceField.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b4917350728a690a7b14ddd2c78f2b18a009c5a93663cf7b8853913951b58a6 -size 8265 +oid sha256:ddf6d7c9411162a9e6ba9a762d8c95374a3c78b2ca9ee34c5695869eb56cbf6b +size 8375 diff --git a/Source/Shaders/GlobalSignDistanceField.hlsl b/Source/Shaders/GlobalSignDistanceField.hlsl index 5bd516f92..26bbc7957 100644 --- a/Source/Shaders/GlobalSignDistanceField.hlsl +++ b/Source/Shaders/GlobalSignDistanceField.hlsl @@ -76,6 +76,37 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex[4], float3 return distance; } +// 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 tex[4], float3 worldPosition, uint minCascade = 0) +{ + float3 gradient = float3(0, 0.00001f, 0); + float distance = data.CascadePosDistance[3].w * 2.0f; + if (distance <= 0.0f) + return gradient; + UNROLL + for (uint cascade = minCascade; cascade < 4; cascade++) + { + float4 cascadePosDistance = data.CascadePosDistance[cascade]; + float cascadeMaxDistance = cascadePosDistance.w * 2; + float3 posInCascade = worldPosition - cascadePosDistance.xyz; + float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f; + float cascadeDistance = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0); + if (cascadeDistance < 0.9f && !any(cascadeUV < 0) && !any(cascadeUV > 1)) + { + float texelOffset = 0.5f / 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; + gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance; + break; + } + } + return gradient; +} + // Ray traces the Global SDF. GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D tex[4], Texture3D mips[4], const GlobalSDFTrace trace, uint minCascade = 0) { diff --git a/Source/Shaders/GlobalSignDistanceField.shader b/Source/Shaders/GlobalSignDistanceField.shader index 8b4d4d69f..dac95b00c 100644 --- a/Source/Shaders/GlobalSignDistanceField.shader +++ b/Source/Shaders/GlobalSignDistanceField.shader @@ -210,6 +210,7 @@ float4 PS_Debug(Quad_VS2PS input) : SV_Target float3 color = saturate(hit.StepsCount / 80.0f).xxx; if (!hit.IsHit()) color.rg *= 0.4f; + //else color.rgb = normalize(SampleGlobalSDFGradient(GlobalSDF, GlobalSDFTex, hit.GetHitPosition(trace))); return float4(color, 1); }