diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 05ba680c81fb1b6a8ffa562e19b877c137bd4e96..794b800146bf05e8501dd4c8f52c9d3c07f1ec58 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -129,7 +129,8 @@ r.MobileHDR=False r.MSAACount=4 r.Mobile.ShadingPath=1 r.ForwardShading=True -r.CustomDepth=1 +r.CustomDepth=0 +r.CustomDepthTemporalAAJitter=False [/Script/HardwareTargeting.HardwareTargetingSettings] TargetedHardwareClass = Mobile diff --git a/Content/MagicWandMap.umap b/Content/MagicWandMap.umap index 9f01f84e975af728177b785d429e26e6ba8ef2b2..4e7456218f05c4b5c26de3ca4d0b7adcdecfd53e 100644 Binary files a/Content/MagicWandMap.umap and b/Content/MagicWandMap.umap differ diff --git a/Content/MagicWandPawn.uasset b/Content/MagicWandPawn.uasset index 9472186a5940e9e6147f87a741f1b214548baeff..de43aeb2f5e2148db4609a84bffcf1dd9b746344 100644 Binary files a/Content/MagicWandPawn.uasset and b/Content/MagicWandPawn.uasset differ diff --git a/Source/MetaCastBachelor/MagicWand.cpp b/Source/MetaCastBachelor/MagicWand.cpp index 90a4ca40dd493d2c141ab7430ad3af5b7c5d8287..39877f5160954d8f4647d7eddf17670a1049b871 100644 --- a/Source/MetaCastBachelor/MagicWand.cpp +++ b/Source/MetaCastBachelor/MagicWand.cpp @@ -1,5 +1,6 @@ #include "MagicWand.h" #include "Utilities.h" +#include "Components/LineBatchComponent.h" #include "Generators/MarchingCubes.h" // INITIALIZATION @@ -8,6 +9,7 @@ UMagicWand::UMagicWand() : World(nullptr) { // Create the procedural mesh component ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("GeneratedMesh")); + MyLineBatchComponent = CreateDefaultSubobject<ULineBatchComponent>(TEXT("LineDrawer")); } void UMagicWand::BeginPlay() @@ -20,7 +22,7 @@ void UMagicWand::BeginPlay() void UMagicWand::InitProceduralMesh() const { - ProceduralMesh->AttachToComponent(MyPointCloud->PointCloudVisualizer, FAttachmentTransformRules::SnapToTargetIncludingScale); + //ProceduralMesh->AttachToComponent(MyPointCloud->PointCloudVisualizer, FAttachmentTransformRules::SnapToTargetIncludingScale); ProceduralMesh->SetMaterial(0, SelectionVolumeMat); ProceduralMesh->SetMaterial(1, SelectionVolumeMat); ProceduralMesh->SetMaterial(2, SelectionVolumeMat); @@ -182,39 +184,113 @@ void UMagicWand::GenerateVoxelMeshSmooth(const TArray<int32> Voxels) FScopeLock MeshLock(&ProceduralMeshGuard); ProceduralMesh->CreateMeshSection(0, Vertices, Indices, Normals, TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false); ProceduralMesh->SetVisibility(true); - AccumulatedTime.Store(0); IsMarchingCubesRunning = false; }); }); } +void UMagicWand::DrawPersistentLine(const FVector& Start, const FVector& End, const FColor& Color, const float Duration, const float Thickness) const +{ + if (MyLineBatchComponent) + { + MyLineBatchComponent->DrawLine(Start, End, Color, 0, Thickness, Duration); + } +} + +void UMagicWand::GenerateCylinderBetweenPoints(const FVector& Start, const FVector& End, const float Radius, const int32 NumSides, const FColor Color, const int MeshSectionIndex) const +{ + FVector Axis = End - Start; + Axis.Normalize(); + + TArray<FVector> Vertices; + TArray<int32> Triangles; + TArray<FVector> Normals; + TArray<FVector2D> UVs; + TArray<FProcMeshTangent> Tangents; + + // Bottom cap + int32 VertIndex = 0; + Vertices.Add(Start); // Center bottom + Normals.Add(-Axis); + UVs.Add(FVector2D(0.5f, 0.5f)); + for (int i = 0; i <= NumSides; i++) + { + const float Angle = FMath::DegreesToRadians((360.f / NumSides) * i); + FVector Point = Start + Radius * FVector(FMath::Cos(Angle), FMath::Sin(Angle), 0); + Vertices.Add(Point); + Normals.Add(-Axis); + UVs.Add(FVector2D(FMath::Cos(Angle) * 0.5f + 0.5f, FMath::Sin(Angle) * 0.5f + 0.5f)); + + if (i > 0) + { + Triangles.Add(VertIndex); + Triangles.Add(VertIndex + i); + Triangles.Add(VertIndex + i + 1); + } + } + + // Side faces + const int32 BottomCenterIndex = VertIndex; + const int32 TopCenterIndex = Vertices.Num(); + Vertices.Add(End); // Center top + Normals.Add(Axis); + UVs.Add(FVector2D(0.5f, 0.5f)); + VertIndex++; + for (int i = 0; i <= NumSides; i++) + { + const float Angle = FMath::DegreesToRadians((360.f / NumSides) * i); + FVector Point = End + Radius * FVector(FMath::Cos(Angle), FMath::Sin(Angle), 0); + Vertices.Add(Point); + Normals.Add(Axis); + UVs.Add(FVector2D(FMath::Cos(Angle) * 0.5f + 0.5f, FMath::Sin(Angle) * 0.5f + 0.5f)); + + if (i > 0) + { + // Connect bottom and top + Triangles.Add(BottomCenterIndex + i); + Triangles.Add(TopCenterIndex + i); + Triangles.Add(BottomCenterIndex + i + 1); + + Triangles.Add(TopCenterIndex + i); + Triangles.Add(TopCenterIndex + i + 1); + Triangles.Add(BottomCenterIndex + i + 1); + } + } + + TArray<FLinearColor> VertexColors; + VertexColors.Init(Color, Vertices.Num()); + + // Create mesh + ProceduralMesh->CreateMeshSection_LinearColor(MeshSectionIndex, Vertices, Triangles, Normals, TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false); +} + // INPUT HANDLING +void UMagicWand::HandleMetaSelectPressed(const FInputActionInstance& Instance) +{ + Super::HandleMetaSelectPressed(Instance); + + const FVector SelectionStartPositionWorld = SelectionObject->GetComponentLocation(); + const FVector SelectionStartPositionLocal = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(SelectionStartPositionWorld); + + FindSeed(SelectionStartPositionLocal); +} + void UMagicWand::HandleMetaSelectReleased(const FInputActionInstance& Instance) { Super::HandleMetaSelectReleased(Instance); const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation(); const FVector SelectionLocalPosition = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(SelectionWorldPosition); - - ProximityThreshold = FMath::Clamp(FVector::Dist(SelectionStartPosition, SelectionLocalPosition) / 10, 0.1, 8); - + InitMagicWandSelection(); AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this, &SelectionLocalPosition]() { - PerformMagicWandSelection(SelectionStartPosition); + PerformMagicWandSelection(); }); } -void UMagicWand::HandleMetaSelectPressed(const FInputActionInstance& Instance) -{ - Super::HandleMetaSelectPressed(Instance); - - const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation(); - SelectionStartPosition = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(SelectionWorldPosition); -} - void UMagicWand::HandleMetaEraseReleased(const FInputActionInstance& Instance) { Super::HandleMetaEraseReleased(Instance); @@ -235,11 +311,10 @@ void UMagicWand::InitMagicWandSelection() { ProceduralMesh->ClearAllMeshSections(); AbortMarchingCubes = true; - if(AccumulatedTime.Load() >= 0) AccumulatedTime.Store(1 / EvaluationsPerSecond); AbortMagicWand.Store(false); } -void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition) +void UMagicWand::PerformMagicWandSelection() { if (MyPointCloud->SelectionFlags.Num() != MyPointCloud->PositionVectors.Num()) { @@ -250,28 +325,22 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition) //UE_LOG(LogTemp, Warning, TEXT("Starting MagicWand Selection!")); // Find the closest point to the input position as the seed - int32 SeedIndex; - const int32 InputVoxelIndex = MyDensityField->WorldPositionToIndex(InputPosition); - FindSeedIndex(InputPosition, InputVoxelIndex, SeedIndex); - if (SeedIndex != INDEX_NONE) + if (SeedPointIndex != INDEX_NONE) { - ExpandSelectionFromPointIndex(SeedIndex); - }else - { - AccumulatedTime.Store( 0); + ExpandSelectionFromPointIndex(SeedPointIndex); } } -void UMagicWand::FindSeedIndex(const FVector& InputPosition, const int32 InputVoxelIndex, int32& SeedIndex) const +void UMagicWand::FindSeed(const FVector& InputPosition) { + const int32 InputVoxelIndex = MyDensityField->WorldPositionToIndex(InputPosition); TArray<int32> Neighbors = MyDensityField->IndexToVoxelNeighbors(InputVoxelIndex); Neighbors.Add(InputVoxelIndex); - - SeedIndex = INDEX_NONE; float MinDistance = FLT_MAX; + SeedPointIndex = INDEX_NONE; - for(int NeighborDistance = 0; NeighborDistance < 4; ++NeighborDistance) + for(int NeighborDistance = 0; NeighborDistance < 5; ++NeighborDistance) { const int NumNeighbors = Neighbors.Num(); @@ -289,26 +358,30 @@ void UMagicWand::FindSeedIndex(const FVector& InputPosition, const int32 InputVo } } } - - + for (const int CurrentNeighborIndex : Neighbors) { TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentNeighborIndex); for(const int32 CurrentIndex : PointIndices) { - FVector CurrentPosition = MyDensityField->IndexToVoxelPosition(CurrentIndex); + FVector CurrentPosition = MyPointCloud->PositionVectors[CurrentIndex]; const float Distance = FVector::Dist(InputPosition, CurrentPosition); if (Distance < MinDistance) { MinDistance = Distance; - SeedIndex = CurrentIndex; + SeedPointIndex = CurrentIndex; } } } + + if(SeedPointIndex != INDEX_NONE) + { + SeedPointPositionLocal = MyPointCloud->PositionVectors[SeedPointIndex]; + } } -void UMagicWand::ExpandSelectionFromPointIndex(const int32 SeedIndex) +void UMagicWand::ExpandSelectionFromPointIndex(const int32 PointIndex) { { FScopeLock Lock(&ThreadNumberLock); @@ -316,8 +389,8 @@ void UMagicWand::ExpandSelectionFromPointIndex(const int32 SeedIndex) } TQueue<int32>* ProcessQueue = new TQueue<int32>{}; - ProcessQueue->Enqueue(SeedIndex); - MyPointCloud->SelectionFlags[SeedIndex] = true; + ProcessQueue->Enqueue(PointIndex); + MyPointCloud->SelectionFlags[PointIndex] = true; const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold; int NumberToProcess = 0; @@ -419,7 +492,6 @@ void UMagicWand::AbortSelection() //UE_LOG(LogTemp, Warning, TEXT("Thread Closed! Number of Threads now: %d"), NumberThreads.GetValue()); if(NumberThreads.GetValue() == 0) { - AccumulatedTime.Store(0); //AbortMagicWand.Store(false); //UE_LOG(LogTemp, Warning, TEXT("Aborted!")); }else if(NumberThreads.GetValue() < 0) @@ -460,11 +532,16 @@ void UMagicWand::TickComponent(const float DeltaTime, const ELevelTick TickType, void UMagicWand::SelectParticles(const FVector& InputPosition) { - if (AccumulatedTime.Load() >= 1 / EvaluationsPerSecond) - { - AccumulatedTime.Store(FLT_MIN); - } + const FVector CurrentSelectionPositionWorld = SelectionObject->GetComponentLocation(); + const FVector CurrentSelectionPositionLocal = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(CurrentSelectionPositionWorld); + ProximityThreshold = FMath::Clamp(FVector::Dist(SeedPointPositionLocal, CurrentSelectionPositionLocal) / ThresholdDistanceScaling, MinThreshold, MaxThreshold); - const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation(); - DrawDebugLine(World, SelectionWorldPosition, MyPointCloud->PointCloudVisualizer->GetComponentTransform().TransformPosition(SelectionStartPosition), FColor::Red, false, 0, 0, 0.1f); + const FVector SelectionDirectionLocal = CurrentSelectionPositionLocal - SeedPointPositionLocal; + const FVector ProximityEndPointLocal = SeedPointPositionLocal + (SelectionDirectionLocal.GetSafeNormal() * ProximityThreshold); + + const FVector SelectionStartPositionWorld = MyPointCloud->PointCloudVisualizer->GetComponentTransform().TransformPosition(SeedPointPositionLocal); + const FVector ProximityEndPointWorld = MyPointCloud->PointCloudVisualizer->GetComponentTransform().TransformPosition(ProximityEndPointLocal); + + GenerateCylinderBetweenPoints(SelectionStartPositionWorld, ProximityEndPointWorld, 0.05, 8, FColor::Red, 1); + GenerateCylinderBetweenPoints((CurrentSelectionPositionWorld - ProximityEndPointWorld).GetSafeNormal() * 0.05 + ProximityEndPointWorld, CurrentSelectionPositionWorld, 0.05, 8, FColor::Green, 0); } \ No newline at end of file diff --git a/Source/MetaCastBachelor/MagicWand.h b/Source/MetaCastBachelor/MagicWand.h index 0037e3b9903341dbef0a4d4090f9e6e4d506cf2d..683796acda160ae94acbef6a60ae2811326ea7ba 100644 --- a/Source/MetaCastBachelor/MagicWand.h +++ b/Source/MetaCastBachelor/MagicWand.h @@ -25,19 +25,27 @@ class UMagicWand : public UMetaCastBaseline UProceduralMeshComponent* ProceduralMesh; UPROPERTY() UWorld* World; - TAtomic<float> AccumulatedTime = 0.0; - FVector SelectionStartPosition; + FVector SeedPointPositionLocal; + UPROPERTY() + ULineBatchComponent* MyLineBatchComponent; + float ProximityThreshold = 0.1f; + float MarchingCubeSize = 0; + int32 SeedPointIndex; // USER EXPORTED UPROPERTY(EditAnywhere) - float MarchingCubeSize = 0; + float ThresholdDistanceScaling = 20; + UPROPERTY(EditAnywhere) - int EvaluationsPerSecond = 10; + float MinThreshold = 0.1; + UPROPERTY(EditAnywhere) - float ProximityThreshold = 0.1f; + float MaxThreshold = 8; + UPROPERTY(EditAnywhere) UMaterialInterface* SelectionVolumeMat; + UPROPERTY(EditAnywhere) int MaxThreadCount = 100; @@ -64,9 +72,10 @@ public: // MAGIC WAND SELECTION void InitMagicWandSelection(); - void FindSeedIndex(const FVector& InputPosition, int32 InputVoxelIndex, int32& SeedIndex) const; - void PerformMagicWandSelection(const FVector& InputPosition); - void ExpandSelectionFromPointIndex(int32 SeedIndex); + void FindSeedIndex(const FVector& InputPosition, int32& SeedIndex) const; + void PerformMagicWandSelection(); + void FindSeed(const FVector& InputPosition); + void ExpandSelectionFromPointIndex(int32 PointIndex); void ExpandSelectionFromPointIndexQueue(TQueue<int32>* ProcessQueue); void ExpandThroughNeighborsInRange(TQueue<int32>* ProcessQueue, const float SquaredProximityThreshold, int& NumberToProcess, const FVector& CurrentQueuePointPosition) const; void AbortSelection(); @@ -76,4 +85,6 @@ public: virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void SelectParticles(const FVector& InputPosition) override; + void DrawPersistentLine(const FVector& Start, const FVector& End, const FColor& Color, float Duration, float Thickness) const; + void GenerateCylinderBetweenPoints(const FVector& Start, const FVector& End, const float Radius, const int32 NumSides, const FColor Color, const int MeshSectionIndex) const; }; \ No newline at end of file