Various improvements for SDF rendering

This commit is contained in:
Wojciech Figat
2022-04-29 17:11:39 +02:00
parent 5465652466
commit 8428f28239
9 changed files with 28 additions and 16 deletions

Binary file not shown.

View File

@@ -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;
/// <inheritdoc />
public ModelWindow(Editor editor, AssetItem item)

View File

@@ -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

View File

@@ -213,8 +213,9 @@ public:
/// <param name="resolutionScale">The SDF texture resolution scale. Use higher values for more precise data but with significant performance and memory overhead.</param>
/// <param name="lodIndex">The index of the LOD to use for the SDF building.</param>
/// <param name="cacheData">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.</param>
/// <param name="backfacesThreshold">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.</param>
/// <returns>True if failed, otherwise false.</returns>
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);
/// <summary>
/// Sets set SDF data (releases the current one).

View File

@@ -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)
{

View File

@@ -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<void(int32)> sdfJob = [&sdf, &resolution, &sampleDirections, &scene, &voxels, &xyzToLocalMul, &xyzToLocalAdd, &encodeMAD, &formatStride, &formatWrite](int32 z)
Function<void(int32)> 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;

View File

@@ -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:

View File

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

View File

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