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]);