diff --git a/Content/BP_PointCloud.uasset b/Content/BP_PointCloud.uasset index b730c627f98a9a952404a479005bc656cb881805..630f4bc467f5517f4b0d0712ef2c32feeb0479c6 100644 Binary files a/Content/BP_PointCloud.uasset and b/Content/BP_PointCloud.uasset differ diff --git a/Content/MagicWandMap.umap b/Content/MagicWandMap.umap index 1db0e16a514f1f959cebb98ac2a2e703aacb7123..bd7492ae734fcd1e7e27825d4ae8845abe574fec 100644 Binary files a/Content/MagicWandMap.umap and b/Content/MagicWandMap.umap differ diff --git a/Plugins/UEPlugin-Kdtree b/Plugins/UEPlugin-Kdtree new file mode 160000 index 0000000000000000000000000000000000000000..94ef56d465cf19d96e17b6e34c3a3739e1384a7e --- /dev/null +++ b/Plugins/UEPlugin-Kdtree @@ -0,0 +1 @@ +Subproject commit 94ef56d465cf19d96e17b6e34c3a3739e1384a7e diff --git a/Source/MetaCastBachelor/MagicWand.cpp b/Source/MetaCastBachelor/MagicWand.cpp index 85419994c0a810256f93296032dbcb11374cb068..4b2f64b31da4379dd4a162aac5eccaa57b57b51b 100644 --- a/Source/MetaCastBachelor/MagicWand.cpp +++ b/Source/MetaCastBachelor/MagicWand.cpp @@ -1,4 +1,6 @@ #include "MagicWand.h" + +#include "KdtreeBPLibrary.h" #include "Utilities.h" #include "Generators/MarchingCubes.h" @@ -88,7 +90,7 @@ void UMagicWand::InitMagicWandSelection() World = GetWorld(); AbortMarchingCubes = true; - AccumulatedTime = 0.0f; + //AccumulatedTime = 0.0f; } void UMagicWand::SelectParticles(const FVector& InputPosition) @@ -96,7 +98,8 @@ void UMagicWand::SelectParticles(const FVector& InputPosition) if (AccumulatedTime >= 1 / EvaluationsPerSecond) { AccumulatedTime = -10000; - + + UE_LOG(LogTemp, Warning, TEXT("Input recognized!")); AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this]() { const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation(); @@ -104,7 +107,7 @@ void UMagicWand::SelectParticles(const FVector& InputPosition) PerformMagicWandSelection(SelectionLocalPosition); - UE_LOG(LogTemp, Warning, TEXT("Calculations done!")); + //UE_LOG(LogTemp, Warning, TEXT("Calculations done!")); }); } @@ -118,6 +121,8 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition) return; } + UE_LOG(LogTemp, Warning, TEXT("Starting Selection!")); + //UE_LOG(LogTemp, Warning, TEXT("Looking for Seed Index:")); // Find the closest point to the input position as the seed const int32 InputVoxelIndex = MyDensityField->WorldPositionToIndex(InputPosition); @@ -126,21 +131,42 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition) int32 SeedIndex = INDEX_NONE; float MinDistance = FLT_MAX; - for (const int CurrentNeighborIndex : Neighbors) - { - TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentNeighborIndex); - for(const int32 CurrentIndex : PointIndices) - { - FVector CurrentPosition = MyDensityField->IndexToVoxelPosition(CurrentIndex); - const float Distance = FVector::Dist(InputPosition, CurrentPosition); - if (Distance < MinDistance) - { - MinDistance = Distance; - SeedIndex = CurrentIndex; - } - } - } + for(int NeighborDistance = 0; NeighborDistance < 3; ++NeighborDistance) + { + const int NumNeighbors = Neighbors.Num(); + + for (int i = 0; i < NumNeighbors; ++i) + { + const int CurrentNeighborIndex = Neighbors[i]; + TArray<int32> NeighborsOfNeighbors = MyDensityField->IndexToVoxelNeighbors(CurrentNeighborIndex); + + for (int CurrentNeighborOfNeighborIndex : NeighborsOfNeighbors) + { + if (!Neighbors.Contains(CurrentNeighborOfNeighborIndex)) + { + Neighbors.Add(CurrentNeighborOfNeighborIndex); + } + } + } + } + + + for (const int CurrentNeighborIndex : Neighbors) + { + TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentNeighborIndex); + + for(const int32 CurrentIndex : PointIndices) + { + FVector CurrentPosition = MyDensityField->IndexToVoxelPosition(CurrentIndex); + const float Distance = FVector::Dist(InputPosition, CurrentPosition); + if (Distance < MinDistance) + { + MinDistance = Distance; + SeedIndex = CurrentIndex; + } + } + } if (SeedIndex != INDEX_NONE) { @@ -149,80 +175,76 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition) //Expand selection from the seed ExpandSelection(SeedIndex); + }else + { + AccumulatedTime = 0; } - - } void UMagicWand::ExpandSelection(const int32 SeedIndex) { + UE_LOG(LogTemp, Warning, TEXT("Expanding!")); TQueue<int32> ToProcess; ToProcess.Enqueue(SeedIndex); SelectedClusterIndices.Add(SeedIndex); MyPointCloud->SelectionFlags[SeedIndex] = true; + + const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold; + TArray<int> Indices; + TArray<FVector> Data; while (!ToProcess.IsEmpty()) { int32 CurrentQueuePointIndex; ToProcess.Dequeue(CurrentQueuePointIndex); - FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex]; + const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex]; - const int32 CurrentVoxelQueueIndex = MyDensityField->WorldPositionToIndex(CurrentQueuePointPosition); - - /* - TArray<int32> Neighbors = MyDensityField->IndexToVoxelNeighbors(CurrentVoxelQueueIndex); - Neighbors.Add(CurrentVoxelQueueIndex); + Indices.Empty(); + Data.Empty(); - for (const int CurrentVoxelNeighborIndex : Neighbors) - { - TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentVoxelNeighborIndex); - - for(const int32 CurrentPointComparisonIndex : PointIndices) - { - if(MyPointCloud->SelectionFlags[CurrentPointComparisonIndex]) - { - continue; - } - FVector CurrentComparisonPosition = MyDensityField->IndexToVoxelPosition(CurrentPointComparisonIndex); - - if (FVector::Dist(CurrentQueuePointPosition, CurrentComparisonPosition) <= ProximityThreshold) - { - ToProcess.Enqueue(CurrentPointComparisonIndex); - SelectedClusterIndices.Add(CurrentPointComparisonIndex); - MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true; - } - } - }*/ - // ------------------- + UKdtreeBPLibrary::CollectFromKdtree(MyPointCloud->MyKdTree, CurrentQueuePointPosition, MyPointCloud->InfluenceRadius, Indices, Data); + for(int i = 0; i < Indices.Num(); ++i) + { + const int CurrentPointComparisonIndex = Indices[i]; + + if(MyPointCloud->SelectionFlags[CurrentPointComparisonIndex]) + { + continue; + } + + ToProcess.Enqueue(CurrentPointComparisonIndex); + MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true; + } + + /* const int32 StartX = FMath::Max(0, FMath::FloorToInt((CurrentQueuePointPosition.X - ProximityThreshold - MyPointCloud->MinBounds.X) / MyDensityField->GetStep().X)); const int32 EndX = FMath::Min(MyDensityField->GetXNum() - 1, FMath::FloorToInt((CurrentQueuePointPosition.X + ProximityThreshold - MyPointCloud->MinBounds.X) / MyDensityField->GetStep().X)); const int32 StartY = FMath::Max(0, FMath::FloorToInt((CurrentQueuePointPosition.Y - ProximityThreshold - MyPointCloud->MinBounds.Y) / MyDensityField->GetStep().Y)); const int32 EndY = FMath::Min(MyDensityField->GetYNum() - 1, FMath::FloorToInt((CurrentQueuePointPosition.Y + ProximityThreshold - MyPointCloud->MinBounds.Y) / MyDensityField->GetStep().Y)); const int32 StartZ = FMath::Max(0, FMath::FloorToInt((CurrentQueuePointPosition.Z - ProximityThreshold - MyPointCloud->MinBounds.Z) / MyDensityField->GetStep().Z)); const int32 EndZ = FMath::Min(MyDensityField->GetZNum() - 1, FMath::FloorToInt((CurrentQueuePointPosition.Z + ProximityThreshold - MyPointCloud->MinBounds.Z) / MyDensityField->GetStep().Z)); - - - /* + + UE_LOG(LogTemp, Warning, TEXT("CurrentQueuePointPosition: %s"), *CurrentQueuePointPosition.ToString()); UE_LOG(LogTemp, Warning, TEXT("StartX: %d"), StartX); UE_LOG(LogTemp, Warning, TEXT("EndX: %d"), EndX); UE_LOG(LogTemp, Warning, TEXT("StartY: %d"), StartY); UE_LOG(LogTemp, Warning, TEXT("EndY: %d"), EndY); UE_LOG(LogTemp, Warning, TEXT("StartZ: %d"), StartZ); - UE_LOG(LogTemp, Warning, TEXT("EndZ: %d"), EndZ);*/ + UE_LOG(LogTemp, Warning, TEXT("EndZ: %d"), EndZ); - ParallelFor(EndZ - StartZ + 1, [&](const int32 ZOffset) { - const int32 Z = StartZ + ZOffset; - + for (int32 Z = StartZ; Z <= EndZ; ++Z) + { for (int32 Y = StartY; Y <= EndY; ++Y) { for (int32 X = StartX; X <= EndX; ++X) { const int32 CurrentVoxelComparisonIndex = MyDensityField->GridPositionToIndex(X, Y, Z); + /* if(!MyDensityField->IsValidIndex(CurrentVoxelComparisonIndex)) { continue; @@ -238,26 +260,21 @@ void UMagicWand::ExpandSelection(const int32 SeedIndex) } FVector CurrentComparisonPosition = MyPointCloud->PositionVectors[CurrentPointComparisonIndex]; - const double Distance = FVector::Distance(CurrentQueuePointPosition, CurrentComparisonPosition); - - //UE_LOG(LogTemp, Warning, TEXT("CurrentQueuePointPosition: %s"), *CurrentQueuePointPosition.ToString()); - //UE_LOG(LogTemp, Warning, TEXT("CurrentComparisonPosition: %s"), *CurrentComparisonPosition.ToString()); + const double SquaredDistance = FVector::DistSquared(CurrentQueuePointPosition, CurrentComparisonPosition); - //UE_LOG(LogTemp, Warning, TEXT("Distance: %f"), Distance); - - if (Distance <= ProximityThreshold) + if (SquaredDistance <= SquaredProximityThreshold) { ToProcess.Enqueue(CurrentPointComparisonIndex); - SelectedClusterIndices.Add(CurrentPointComparisonIndex); + //SelectedClusterIndices.Add(CurrentPointComparisonIndex); MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true; } } } } - }); - + }*/ } + UE_LOG(LogTemp, Warning, TEXT("Calculations done!")); AccumulatedTime = 0; } diff --git a/Source/MetaCastBachelor/MagicWand.h b/Source/MetaCastBachelor/MagicWand.h index a59cde4361a78a9264d4b423cff265ffddc52c9b..e84de2e169ddbefc7983caa6f739693055a0104a 100644 --- a/Source/MetaCastBachelor/MagicWand.h +++ b/Source/MetaCastBachelor/MagicWand.h @@ -30,6 +30,7 @@ class UMagicWand : public UMetaCastBaseline float MarchingCubeSize = 0; UPROPERTY(EditAnywhere) int EvaluationsPerSecond = 10; + UPROPERTY(EditAnywhere) float AccumulatedTime = 0.0; UPROPERTY(EditAnywhere) float ProximityThreshold = 0.1f; diff --git a/Source/MetaCastBachelor/MetaCastBachelor.Build.cs b/Source/MetaCastBachelor/MetaCastBachelor.Build.cs index 89ad2bf109f5efc435ddf3eb31f0c0a180427878..26018c6cd8b8a9be0fbf29a9ff606fc2c9973a1b 100644 --- a/Source/MetaCastBachelor/MetaCastBachelor.Build.cs +++ b/Source/MetaCastBachelor/MetaCastBachelor.Build.cs @@ -10,7 +10,7 @@ public class MetaCastBachelor : ModuleRules PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent", "EnhancedInput"}); - PrivateDependencyModuleNames.AddRange(new string[] {"GPUPointCloudRenderer", "GPUPointCloudRendererEditor", "RWTHVRToolkit", "ProceduralMeshComponent"}); + PrivateDependencyModuleNames.AddRange(new string[] {"GPUPointCloudRenderer", "GPUPointCloudRendererEditor", "RWTHVRToolkit", "ProceduralMeshComponent", "Kdtree"}); // Uncomment if you are using Slate UI // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); diff --git a/Source/MetaCastBachelor/MetaPoint.cpp b/Source/MetaCastBachelor/MetaPoint.cpp index 2e908f081531254cac5f4c038fb546e1cd7c5f26..e42fe892d1832d81a714777f8d1bc68910814102 100644 --- a/Source/MetaCastBachelor/MetaPoint.cpp +++ b/Source/MetaCastBachelor/MetaPoint.cpp @@ -1,7 +1,6 @@ #include "MetaPoint.h" #include "Utilities.h" #include "Generators/MarchingCubes.h" -#include "UObject/GCObjectScopeGuard.h" UMetaPoint::UMetaPoint() : LocalMaximumIndex(0), MyDensityField(nullptr), MetaPointThreshold(0), World(nullptr) { diff --git a/Source/MetaCastBachelor/PointCloud.cpp b/Source/MetaCastBachelor/PointCloud.cpp index d319ce91f39e29ecdb9443e723229bac0bd796cc..a5f6813ffe3a9127732fc9946fb34915cc576035 100644 --- a/Source/MetaCastBachelor/PointCloud.cpp +++ b/Source/MetaCastBachelor/PointCloud.cpp @@ -1,9 +1,10 @@ #include "PointCloud.h" +#include "KdtreeBPLibrary.h" #include "PointCloudDataReader.h" // Sets default values APointCloud::APointCloud() - : MyDensityField(nullptr), PointCloudVisualizer(nullptr), SelectedMaterial(nullptr), UnselectedMaterial(nullptr) + : MyDensityField(nullptr), MyKdTree(), PointCloudVisualizer(nullptr), SelectedMaterial(nullptr), UnselectedMaterial(nullptr) { // Set this actor to call Tick() every frame. PrimaryActorTick.bCanEverTick = true; @@ -18,6 +19,10 @@ void APointCloud::BeginPlay() ReadPointCloudFromFile(PointInputData, FlagInputData); InitPointCloudVisualizer(); SetupDensityFieldFromPointCloud(); + + UKdtreeBPLibrary::BuildKdtree(MyKdTree, PositionVectors); + //UKdtreeBPLibrary::DumpKdtreeToConsole(MyKdTree); + UKdtreeBPLibrary::ValidateKdtree(MyKdTree); } void APointCloud::ReadPointCloudFromFile(const FFilePath FileNamePoints, const FFilePath FileNameFlags) diff --git a/Source/MetaCastBachelor/PointCloud.h b/Source/MetaCastBachelor/PointCloud.h index 9de2a628025c9b51483411f91b94d78166a0cca7..68b6499becbfef3bf8418d98dad08bdc37cfb567 100644 --- a/Source/MetaCastBachelor/PointCloud.h +++ b/Source/MetaCastBachelor/PointCloud.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" #include "GPUPointCloudRendererComponent.h" +#include "KdtreeCommon.h" #include "GameFramework/Actor.h" #include "MetaCastBachelor/DensityField.h" #include "PointCloud.generated.h" @@ -12,29 +13,30 @@ class APointCloud : public AActor GENERATED_BODY() public: - UPROPERTY(EditAnywhere) - float InfluenceRadius = 3.0f; - + mutable FCriticalSection DataGuard; FDensityField* MyDensityField; + FVector MinBounds; + FVector MaxBounds; + FKdtree MyKdTree; + UPROPERTY() TArray<FVector> PositionVectors; + UPROPERTY() TArray<bool> DefaultFlags; + UPROPERTY() TArray<bool> SelectionFlags; + UPROPERTY() TArray<FColor> PointColors; - mutable FCriticalSection DataGuard; - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Bounds") - FVector MinBounds; - - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Bounds") - FVector MaxBounds; - UPROPERTY() UGPUPointCloudRendererComponent* PointCloudVisualizer; - + + UPROPERTY(EditAnywhere) + float InfluenceRadius = 3.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Visualization") float SplatSize = 1.0f; @@ -49,8 +51,7 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Materials") UMaterialInterface* UnselectedMaterial; - - // Sets default values for this actor's properties + APointCloud(); void InitPointCloudVisualizer(); void UpdateBounds();