Minor sdf imporvements

This commit is contained in:
Wojtek Figat
2024-05-24 12:41:39 +02:00
parent 7c83481d6f
commit f326fa611f
3 changed files with 17 additions and 19 deletions

View File

@@ -18,6 +18,7 @@
#include "Engine/Content/Assets/Model.h" #include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Content.h" #include "Engine/Content/Content.h"
#include "Engine/Serialization/MemoryWriteStream.h" #include "Engine/Serialization/MemoryWriteStream.h"
#include "Engine/Engine/Units.h"
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Core/Utilities.h" #include "Engine/Core/Utilities.h"
#include "Engine/Core/Types/StringView.h" #include "Engine/Core/Types/StringView.h"
@@ -85,7 +86,7 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
return true; return true;
Float3 size = bounds.GetSize(); Float3 size = bounds.GetSize();
ModelBase::SDFData sdf; ModelBase::SDFData sdf;
sdf.WorldUnitsPerVoxel = 10 / Math::Max(resolutionScale, 0.0001f); sdf.WorldUnitsPerVoxel = METERS_TO_UNITS(0.1f) / Math::Max(resolutionScale, 0.0001f); // 1 voxel per 10 centimeters
Int3 resolution(Float3::Ceil(Float3::Clamp(size / sdf.WorldUnitsPerVoxel, 4, 256))); Int3 resolution(Float3::Ceil(Float3::Clamp(size / sdf.WorldUnitsPerVoxel, 4, 256)));
Float3 uvwToLocalMul = size; Float3 uvwToLocalMul = size;
Float3 uvwToLocalAdd = bounds.Minimum; Float3 uvwToLocalAdd = bounds.Minimum;
@@ -96,7 +97,6 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
sdf.LocalBoundsMax = bounds.Maximum; sdf.LocalBoundsMax = bounds.Maximum;
sdf.ResolutionScale = resolutionScale; sdf.ResolutionScale = resolutionScale;
sdf.LOD = lodIndex; sdf.LOD = lodIndex;
// TODO: maybe apply 1 voxel margin around the geometry?
const int32 maxMips = 3; const int32 maxMips = 3;
const int32 mipCount = Math::Min(MipLevelsCount(resolution.X, resolution.Y, resolution.Z, true), maxMips); const int32 mipCount = Math::Min(MipLevelsCount(resolution.X, resolution.Y, resolution.Z, true), maxMips);
PixelFormat format = PixelFormat::R16_UNorm; PixelFormat format = PixelFormat::R16_UNorm;
@@ -169,21 +169,20 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
// https://www.cse.chalmers.se/~uffe/HighResolutionSparseVoxelDAGs.pdf // https://www.cse.chalmers.se/~uffe/HighResolutionSparseVoxelDAGs.pdf
// Brute-force for each voxel to calculate distance to the closest triangle with point query and distance sign by raycasting around the voxel // Brute-force for each voxel to calculate distance to the closest triangle with point query and distance sign by raycasting around the voxel
const int32 sampleCount = 12; constexpr int32 sampleCount = 12;
Array<Float3> sampleDirections; Float3 sampleDirections[sampleCount];
sampleDirections.Resize(sampleCount);
{ {
RandomStream rand; RandomStream rand;
sampleDirections.Get()[0] = Float3::Up; sampleDirections[0] = Float3::Up;
sampleDirections.Get()[1] = Float3::Down; sampleDirections[1] = Float3::Down;
sampleDirections.Get()[2] = Float3::Left; sampleDirections[2] = Float3::Left;
sampleDirections.Get()[3] = Float3::Right; sampleDirections[3] = Float3::Right;
sampleDirections.Get()[4] = Float3::Forward; sampleDirections[4] = Float3::Forward;
sampleDirections.Get()[5] = Float3::Backward; sampleDirections[5] = Float3::Backward;
for (int32 i = 6; i < sampleCount; i++) for (int32 i = 6; i < sampleCount; i++)
sampleDirections.Get()[i] = rand.GetUnitVector(); sampleDirections[i] = rand.GetUnitVector();
} }
Function<void(int32)> sdfJob = [&sdf, &resolution, &backfacesThreshold, &sampleDirections, &scene, &voxels, &xyzToLocalMul, &xyzToLocalAdd, &encodeMAD, &formatStride, &formatWrite](int32 z) Function<void(int32)> sdfJob = [&sdf, &resolution, &backfacesThreshold, sampleDirections, &sampleCount, &scene, &voxels, &xyzToLocalMul, &xyzToLocalAdd, &encodeMAD, &formatStride, &formatWrite](int32 z)
{ {
PROFILE_CPU_NAMED("Model SDF Job"); PROFILE_CPU_NAMED("Model SDF Job");
Real hitDistance; Real hitDistance;
@@ -203,7 +202,7 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
// Raycast samples around voxel to count triangle backfaces hit // Raycast samples around voxel to count triangle backfaces hit
int32 hitBackCount = 0, hitCount = 0; int32 hitBackCount = 0, hitCount = 0;
for (int32 sample = 0; sample < sampleDirections.Count(); sample++) for (int32 sample = 0; sample < sampleCount; sample++)
{ {
Ray sampleRay(voxelPos, sampleDirections[sample]); Ray sampleRay(voxelPos, sampleDirections[sample]);
if (scene.RayCast(sampleRay, hitDistance, hitNormal, hitTriangle)) if (scene.RayCast(sampleRay, hitDistance, hitNormal, hitTriangle))
@@ -218,7 +217,7 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
float distance = (float)minDistance; float distance = (float)minDistance;
// TODO: surface thickness threshold? shift reduce distance for all voxels by something like 0.01 to enlarge thin geometry // TODO: surface thickness threshold? shift reduce distance for all voxels by something like 0.01 to enlarge thin geometry
// if ((float)hitBackCount > (float)hitCount * 0.3f && hitCount != 0) // if ((float)hitBackCount > (float)hitCount * 0.3f && hitCount != 0)
if ((float)hitBackCount > (float)sampleDirections.Count() * backfacesThreshold && hitCount != 0) if ((float)hitBackCount > (float)sampleCount * backfacesThreshold && hitCount != 0)
{ {
// Voxel is inside the geometry so turn it into negative distance to the surface // Voxel is inside the geometry so turn it into negative distance to the surface
distance *= -1; distance *= -1;

View File

@@ -213,11 +213,11 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
float2 uv = GetDDGIProbeUV(data, cascadeIndex, probeIndex, octahedralCoords, DDGI_PROBE_RESOLUTION_DISTANCE); float2 uv = GetDDGIProbeUV(data, cascadeIndex, probeIndex, octahedralCoords, DDGI_PROBE_RESOLUTION_DISTANCE);
float2 probeDistance = probesDistance.SampleLevel(SamplerLinearClamp, uv, 0).rg * 2.0f; float2 probeDistance = probesDistance.SampleLevel(SamplerLinearClamp, uv, 0).rg * 2.0f;
float probeDistanceMean = probeDistance.x; float probeDistanceMean = probeDistance.x;
float probeDistanceMean2 = probeDistance.y;
// Visibility weight (Chebyshev) // Visibility weight (Chebyshev)
if (biasedPosToProbeDist > probeDistanceMean) if (biasedPosToProbeDist > probeDistanceMean)
{ {
float probeDistanceMean2 = probeDistance.y;
float probeDistanceVariance = abs(Square(probeDistanceMean) - probeDistanceMean2); float probeDistanceVariance = abs(Square(probeDistanceMean) - probeDistanceMean2);
float chebyshevWeight = probeDistanceVariance / (probeDistanceVariance + Square(biasedPosToProbeDist - probeDistanceMean)); float chebyshevWeight = probeDistanceVariance / (probeDistanceVariance + Square(biasedPosToProbeDist - probeDistanceMean));
weight *= max(chebyshevWeight * chebyshevWeight * chebyshevWeight, 0.05f); weight *= max(chebyshevWeight * chebyshevWeight * chebyshevWeight, 0.05f);

View File

@@ -223,7 +223,6 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex, T
float4 cascadePosDistance = data.CascadePosDistance[cascade]; float4 cascadePosDistance = data.CascadePosDistance[cascade];
float voxelSize = data.CascadeVoxelSize[cascade]; float voxelSize = data.CascadeVoxelSize[cascade];
float voxelExtent = voxelSize * 0.5f; float voxelExtent = voxelSize * 0.5f;
float cascadeMinStep = voxelSize;
float3 worldPosition = trace.WorldPosition + trace.WorldDirection * (voxelSize * cascadeTraceStartBias); float3 worldPosition = trace.WorldPosition + trace.WorldDirection * (voxelSize * cascadeTraceStartBias);
// Hit the cascade bounds to find the intersection points // Hit the cascade bounds to find the intersection points
@@ -270,7 +269,7 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex, T
stepDistance *= cascadeMaxDistance; stepDistance *= cascadeMaxDistance;
// Detect surface hit // Detect surface hit
float minSurfaceThickness = voxelExtent * saturate(stepTime / (voxelExtent * 2.0f)); float minSurfaceThickness = voxelExtent * saturate(stepTime / voxelSize);
if (stepDistance < minSurfaceThickness) if (stepDistance < minSurfaceThickness)
{ {
// Surface hit // Surface hit
@@ -293,7 +292,7 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex, T
} }
// Move forward // Move forward
stepTime += max(stepDistance * trace.StepScale, cascadeMinStep); stepTime += max(stepDistance * trace.StepScale, voxelSize);
} }
hit.StepsCount += step; hit.StepsCount += step;
} }