CelticCraft/Plugins/VoxelFree/Source/Voxel/Public/VoxelTools/VoxelDataTools.inl

78 lines
No EOL
2.6 KiB
C++

// Copyright 2020 Phyronnaz
#pragma once
#include "CoreMinimal.h"
#include "VoxelTools/VoxelDataTools.h"
#include "VoxelTools/VoxelToolHelpers.h"
#include "VoxelUtilities/VoxelDistanceFieldUtilities.h"
template<typename T1, typename T2, typename T3>
void UVoxelDataTools::MergeDistanceFieldImpl(
FVoxelData& Data,
const FVoxelIntBox& Bounds,
T1 GetSDF,
T2 MergeSDF,
bool bMultiThreaded,
bool bSetMaterials,
T3 GetMaterial)
{
VOXEL_TOOL_FUNCTION_COUNTER(Bounds.Count());
const FIntVector Size = Bounds.Size();
const TArray<FVoxelValue> Values = Data.ParallelGet<FVoxelValue>(Bounds.Extend(1) /* See GetSurfacePositionsFromDensities */, !bMultiThreaded);
TArray<float> Distances;
TArray<FVector3f> SurfacePositions;
FVoxelDistanceFieldUtilities::GetSurfacePositionsFromDensities(Size, Values, Distances, SurfacePositions);
FVoxelDistanceFieldUtilities::JumpFlood(Size, SurfacePositions, EVoxelComputeDevice::GPU);
FVoxelDistanceFieldUtilities::GetDistancesFromSurfacePositions(Size, SurfacePositions, Distances);
FVoxelDebug::Broadcast("Values", Bounds.Size(), Data.Get<FVoxelValue>(Bounds));
FVoxelDebug::Broadcast("Distances", Bounds.Size(), Distances);
const auto Set = [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value, FVoxelMaterial& Material, auto bSetMaterials_Static)
{
checkVoxelSlow(Bounds.Contains(X, Y, Z));
const float OtherSDF = GetSDF(X, Y, Z);
const float OldSDF = FVoxelUtilities::Get3D(Distances, Size, X, Y, Z, Bounds.Min);
const float NewSDF = MergeSDF(OldSDF, OtherSDF);
Value = FVoxelValue(NewSDF);
if (bSetMaterials_Static)
{
Material = GetMaterial(OldSDF, NewSDF, Material);
}
};
if (bSetMaterials)
{
Data.ParallelSet<FVoxelValue, FVoxelMaterial>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value, FVoxelMaterial& Material)
{
Set(X, Y, Z, Value, Material, FVoxelUtilities::FTrueType());
}, !bMultiThreaded);
}
else
{
// TODO optional
// TODO check surface position is in bounds
Data.ParallelSet<FVoxelMaterial>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelMaterial& Material)
{
const FVector3f SurfacePosition = FVoxelUtilities::Get3D(SurfacePositions, Size, X, Y, Z, Bounds.Min);
const auto Result = FindClosestNonEmptyVoxelImpl(Data, FVoxelVector(Bounds.Min) + FVector(SurfacePosition), true);
if (Result.bSuccess)
{
Material = Result.Material;
}
}, !bMultiThreaded);
Data.ParallelSet<FVoxelValue>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value)
{
FVoxelMaterial Material;
Set(X, Y, Z, Value, Material, FVoxelUtilities::FFalseType());
}, !bMultiThreaded);
}
}