diff --git a/Content/Shaders/GlobalSignDistanceField.flax b/Content/Shaders/GlobalSignDistanceField.flax
index b07e84262..f30c01874 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:618c12f75584c82a5e64a0161ef94b02373af3d5497d9f292dcdbd90d716b62a
+oid sha256:ce0651af73a6bc605cb88d6a747f0d241d15062c19c8359c783138e476c9b0d3
size 10943
diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs
index d493cd0e6..f3197660c 100644
--- a/Source/Editor/Windows/Assets/ModelWindow.cs
+++ b/Source/Editor/Windows/Assets/ModelWindow.cs
@@ -201,6 +201,13 @@ namespace FlaxEditor.Windows.Assets
resolution.FloatValue.MaxValue = 100.0f;
resolution.FloatValue.Value = sdf.Texture != null ? sdf.ResolutionScale : 1.0f;
resolution.FloatValue.BoxValueChanged += b => { proxy.Window._importSettings.SDFResolution = b.Value; };
+ proxy.Window._importSettings.SDFResolution = sdf.ResolutionScale;
+
+ var backfacesThreshold = group.FloatValue("Backfaces Threshold", "Custom threshold (in range 0-1) for adjusting mesh internals detection based on the percentage of test rays hit triangle backfaces. Use lower value for more dense mesh.");
+ backfacesThreshold.FloatValue.MinValue = 0.001f;
+ backfacesThreshold.FloatValue.MaxValue = 1.0f;
+ backfacesThreshold.FloatValue.Value = proxy.Window._backfacesThreshold;
+ backfacesThreshold.FloatValue.BoxValueChanged += b => { proxy.Window._backfacesThreshold = b.Value; };
var lodIndex = group.IntegerValue("LOD Index", "Index of the model Level of Detail to use for SDF data building. By default uses the lowest quality LOD for fast building.");
lodIndex.IntValue.MinValue = 0;
@@ -286,7 +293,7 @@ namespace FlaxEditor.Windows.Assets
private void OnRebuildSDF()
{
var proxy = (MeshesPropertiesProxy)Values[0];
- proxy.Asset.GenerateSDF(proxy.Window._importSettings.SDFResolution, _sdfModelLodIndex.Value);
+ proxy.Asset.GenerateSDF(proxy.Window._importSettings.SDFResolution, _sdfModelLodIndex.Value, true, proxy.Window._backfacesThreshold);
proxy.Window.MarkAsEdited();
Presenter.BuildLayoutOnUpdate();
}
@@ -770,6 +777,7 @@ namespace FlaxEditor.Windows.Assets
private StaticModel _highlightActor;
private MeshDataCache _meshData;
private ModelImportSettings _importSettings = new ModelImportSettings();
+ private float _backfacesThreshold = 0.6f;
///
public ModelWindow(Editor editor, AssetItem item)
diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp
index 4512172f8..a0e994702 100644
--- a/Source/Engine/Content/Assets/Model.cpp
+++ b/Source/Engine/Content/Assets/Model.cpp
@@ -635,7 +635,7 @@ bool Model::Save(bool withMeshDataFromGpu, const StringView& path)
#endif
-bool Model::GenerateSDF(float resolutionScale, int32 lodIndex, bool cacheData)
+bool Model::GenerateSDF(float resolutionScale, int32 lodIndex, bool cacheData, float backfacesThreshold)
{
if (EnableModelSDF == 2)
return true; // Not supported
@@ -658,7 +658,7 @@ bool Model::GenerateSDF(float resolutionScale, int32 lodIndex, bool cacheData)
#else
class MemoryWriteStream* outputStream = nullptr;
#endif
- if (ModelTool::GenerateModelSDF(this, nullptr, resolutionScale, lodIndex, &SDF, outputStream, GetPath()))
+ if (ModelTool::GenerateModelSDF(this, nullptr, resolutionScale, lodIndex, &SDF, outputStream, GetPath(), backfacesThreshold))
return true;
#if USE_EDITOR
diff --git a/Source/Engine/Content/Assets/Model.h b/Source/Engine/Content/Assets/Model.h
index 15744148f..6fde4bab3 100644
--- a/Source/Engine/Content/Assets/Model.h
+++ b/Source/Engine/Content/Assets/Model.h
@@ -213,8 +213,9 @@ public:
/// The SDF texture resolution scale. Use higher values for more precise data but with significant performance and memory overhead.
/// The index of the LOD to use for the SDF building.
/// If true, the generated SDF texture data will be cached on CPU (in asset chunk storage) to allow saving it later, otherwise it will be runtime for GPU-only. Ignored for virtual assets or in build.
+ /// Custom threshold (in range 0-1) for adjusting mesh internals detection based on the percentage of test rays hit triangle backfaces. Use lower value for more dense mesh.
/// True if failed, otherwise false.
- API_FUNCTION() bool GenerateSDF(float resolutionScale = 1.0f, int32 lodIndex = 6, bool cacheData = true);
+ API_FUNCTION() bool GenerateSDF(float resolutionScale = 1.0f, int32 lodIndex = 6, bool cacheData = true, float backfacesThreshold = 0.6f);
///
/// Sets set SDF data (releases the current one).
diff --git a/Source/Engine/Renderer/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GlobalSurfaceAtlasPass.cpp
index 07aa96eaa..52fa4c9dc 100644
--- a/Source/Engine/Renderer/GlobalSurfaceAtlasPass.cpp
+++ b/Source/Engine/Renderer/GlobalSurfaceAtlasPass.cpp
@@ -580,10 +580,13 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
{
// Get the last counter value (accept staging readback delay)
auto data = (uint32*)_culledObjectsSizeBuffer->Map(GPUResourceMapMode::Read);
- uint32 counter = data[surfaceAtlasData.CulledObjectsCounterIndex];
- _culledObjectsSizeBuffer->Unmap();
- if (counter > 0)
- objectsBufferCapacity = counter * sizeof(Vector4);
+ if (data)
+ {
+ uint32 counter = data[surfaceAtlasData.CulledObjectsCounterIndex];
+ _culledObjectsSizeBuffer->Unmap();
+ if (counter > 0)
+ objectsBufferCapacity = counter * sizeof(Vector4);
+ }
}
if (surfaceAtlasData.CulledObjectsCounterIndex == -1)
{
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp
index 8a4cd9a91..fd8575612 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.cpp
+++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp
@@ -66,7 +66,7 @@ ModelSDFMip::ModelSDFMip(int32 mipIndex, const TextureMipData& mip)
{
}
-bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float resolutionScale, int32 lodIndex, ModelBase::SDFData* outputSDF, MemoryWriteStream* outputStream, const StringView& assetName)
+bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float resolutionScale, int32 lodIndex, ModelBase::SDFData* outputSDF, MemoryWriteStream* outputStream, const StringView& assetName, float backfacesThreshold)
{
PROFILE_CPU();
auto startTime = Platform::GetTimeSeconds();
@@ -176,7 +176,7 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
for (int32 i = 6; i < sampleCount; i++)
sampleDirections.Get()[i] = rand.GetUnitVector();
}
- Function sdfJob = [&sdf, &resolution, &sampleDirections, &scene, &voxels, &xyzToLocalMul, &xyzToLocalAdd, &encodeMAD, &formatStride, &formatWrite](int32 z)
+ Function sdfJob = [&sdf, &resolution, &backfacesThreshold, &sampleDirections, &scene, &voxels, &xyzToLocalMul, &xyzToLocalAdd, &encodeMAD, &formatStride, &formatWrite](int32 z)
{
PROFILE_CPU_NAMED("Model SDF Job");
float hitDistance;
@@ -210,8 +210,8 @@ bool ModelTool::GenerateModelSDF(Model* inputModel, ModelData* modelData, float
float distance = minDistance;
// TODO: surface thickness threshold? shift reduce distance for all voxels by something like 0.01 to enlarge thin geometry
- //if ((float)hitBackCount > )hitCount * 0.3f && hitCount != 0)
- if ((float)hitBackCount > (float)sampleDirections.Count() * 0.6f && hitCount != 0)
+ // if ((float)hitBackCount > (float)hitCount * 0.3f && hitCount != 0)
+ if ((float)hitBackCount > (float)sampleDirections.Count() * backfacesThreshold && hitCount != 0)
{
// Voxel is inside the geometry so turn it into negative distance to the surface
distance *= -1;
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h
index 15a7d4def..5af8a84eb 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.h
+++ b/Source/Engine/Tools/ModelTool/ModelTool.h
@@ -185,7 +185,7 @@ public:
// Optional: inputModel or modelData
// Optional: outputSDF or null, outputStream or null
- static bool GenerateModelSDF(class Model* inputModel, class ModelData* modelData, float resolutionScale, int32 lodIndex, ModelBase::SDFData* outputSDF, class MemoryWriteStream* outputStream, const StringView& assetName);
+ static bool GenerateModelSDF(class Model* inputModel, class ModelData* modelData, float resolutionScale, int32 lodIndex, ModelBase::SDFData* outputSDF, class MemoryWriteStream* outputStream, const StringView& assetName, float backfacesThreshold = 0.6f);
#if USE_EDITOR
public:
diff --git a/Source/Shaders/GlobalSignDistanceField.shader b/Source/Shaders/GlobalSignDistanceField.shader
index d07e5f38d..4c2ad666e 100644
--- a/Source/Shaders/GlobalSignDistanceField.shader
+++ b/Source/Shaders/GlobalSignDistanceField.shader
@@ -128,7 +128,7 @@ void CS_RasterizeHeightfield(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId
uint3 voxelCoord = ChunkCoord + DispatchThreadId;
float3 voxelWorldPos = voxelCoord * CascadeCoordToPosMul + CascadeCoordToPosAdd;
float minDistance = MaxDistance * GlobalSDFTex[voxelCoord];
- float thickness = CascadeVoxelSize * -4;
+ float thickness = CascadeVoxelSize * -8;
for (uint i = 0; i < ObjectsCount; i++)
{
ObjectRasterizeData objectData = ObjectsBuffer[Objects[i / 4][i % 4]];
diff --git a/Source/Shaders/GlobalSurfaceAtlas.hlsl b/Source/Shaders/GlobalSurfaceAtlas.hlsl
index b90488cd8..9220f6c26 100644
--- a/Source/Shaders/GlobalSurfaceAtlas.hlsl
+++ b/Source/Shaders/GlobalSurfaceAtlas.hlsl
@@ -194,7 +194,7 @@ float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, ByteAddressBu
continue;
// Remove the scale vector from the transformation matrix
- float3x3 worldToLocal = object.WorldToLocal;
+ float3x3 worldToLocal = (float3x3)object.WorldToLocal;
float scaleX = length(worldToLocal[0]);
float scaleY = length(worldToLocal[1]);
float scaleZ = length(worldToLocal[2]);