Skip to content
Snippets Groups Projects
Commit 492eab0a authored by Timon Römer's avatar Timon Römer
Browse files

optimizes MagicWand by Paralellizing

parent 01357f06
Branches
No related tags found
No related merge requests found
No preview for this file type
#include "MagicWand.h"
#include "KdtreeBPLibrary.h"
#include "Utilities.h"
#include "Generators/MarchingCubes.h"
// INITIALIZATION
UMagicWand::UMagicWand() : World(nullptr)
{
// Create the procedural mesh component
ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("GeneratedMesh"));
SelectedClusterIndices.Reserve(100000);
}
void UMagicWand::BeginPlay()
{
Super::BeginPlay();
World = GetWorld();
if (!World) {
UE_LOG(LogTemp, Warning, TEXT("Invalid world provided."));
InitReferences();
InitProceduralMesh();
}
void UMagicWand::InitProceduralMesh() const
{
ProceduralMesh->AttachToComponent(MyPointCloud->PointCloudVisualizer, FAttachmentTransformRules::SnapToTargetIncludingScale);
ProceduralMesh->SetMaterial(0, SelectionVolumeMat);
ProceduralMesh->SetMaterial(1, SelectionVolumeMat);
......@@ -31,16 +30,22 @@ void UMagicWand::BeginPlay()
ProceduralMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
ProceduralMesh->SetMobility(EComponentMobility::Movable);
ProceduralMesh->SetVisibility(true);
}
void UMagicWand::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
void UMagicWand::InitReferences()
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (!MyPointCloud || !MyPointCloud->MyDensityField) {
UE_LOG(LogTemp, Error, TEXT("Invalid Point Cloud or DensityField provided!"));
}else
{
MyDensityField = MyPointCloud->MyDensityField;
}
AccumulatedTime += DeltaTime;
World = GetWorld();
ProceduralMesh->SetVisibility(Select);
if (!World) {
UE_LOG(LogTemp, Error, TEXT("Invalid world provided."));
}
}
void UMagicWand::EraseParticles(const FVector& InputPosition)
......@@ -48,91 +53,225 @@ void UMagicWand::EraseParticles(const FVector& InputPosition)
}
void UMagicWand::HandleMetaSelectReleased(const FInputActionInstance& Instance)
// VISUALIZATION
void UMagicWand::GenerateVoxelMeshWithCubes(const TArray<int32> Voxels) const
{
Super::HandleMetaSelectReleased(Instance);
TArray<FVector> Vertices;
TArray<int32> Triangles;
TArray<FColor> VertexColors;
// Generate cube vertices and triangles for each voxel
for (const int32 VoxelIndex : Voxels)
{
if(!MyDensityField->IsValidIndex(VoxelIndex))
{
continue;
}
TArray<FVector> VoxelCorners = MyDensityField->IndexToVoxelCornersWorld(VoxelIndex);
// Add vertices for the voxel
const int32 BaseIndex = Vertices.Num();
Vertices.Append(VoxelCorners);
//ProceduralMesh->ClearAllMeshSections();
//ProceduralMesh->SetVisibility(false);
// Define the triangles (12 triangles for 6 faces of the cube)
// Each face of the cube has 2 triangles (6 faces * 2 triangles per face = 12 triangles)
Triangles.Append({
BaseIndex + 0, BaseIndex + 1, BaseIndex + 2, BaseIndex + 0, BaseIndex + 2, BaseIndex + 3, // Bottom face
BaseIndex + 4, BaseIndex + 6, BaseIndex + 5, BaseIndex + 4, BaseIndex + 7, BaseIndex + 6, // Top face
BaseIndex + 0, BaseIndex + 4, BaseIndex + 1, BaseIndex + 1, BaseIndex + 4, BaseIndex + 5, // Front face
BaseIndex + 1, BaseIndex + 5, BaseIndex + 2, BaseIndex + 2, BaseIndex + 5, BaseIndex + 6, // Right face
BaseIndex + 2, BaseIndex + 6, BaseIndex + 3, BaseIndex + 3, BaseIndex + 6, BaseIndex + 7, // Back face
BaseIndex + 3, BaseIndex + 7, BaseIndex + 0, BaseIndex + 0, BaseIndex + 7, BaseIndex + 4 // Left face
});
// Add red color for each corner vertex
for (int32 i = 0; i < 8; ++i)
{
VertexColors.Add(FColor::Green);
}
}
AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this]()
// Create the mesh section
AsyncTask(ENamedThreads::Type::GameThread, [this, Vertices, Triangles, VertexColors]()
{
MyPointCloud->ColorPointsInVoxels(FloodedIndices);
//CreateMeshSections(Vertices, Triangles, VertexColors, 1000);
ProceduralMesh->CreateMeshSection(0, Vertices, Triangles, TArray<FVector>(), TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false);
ProceduralMesh->SetVisibility(true);
});
}
void UMagicWand::HandleMetaSelectPressed(const FInputActionInstance& Instance)
void UMagicWand::GenerateVoxelMeshSmooth(const TArray<int32> Voxels)
{
Super::HandleMetaSelectPressed(Instance);
if(IsMarchingCubesRunning)
return;
InitMagicWandSelection();
}
IsMarchingCubesRunning = true;
void UMagicWand::HandleMetaEraseReleased(const FInputActionInstance& Instance)
FScopeLock Lock(&ProceduralMeshGuard);
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [this, Voxels]()
{
Super::HandleMetaEraseReleased(Instance);
FVector Min(FLT_MAX, FLT_MAX, FLT_MAX);
FVector Max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
//deselect all particles
for (int32 i = 0; i < MyPointCloud->SelectionFlags.Num(); ++i)
for(const int FloodedIndex : Voxels)
{
MyPointCloud->SelectionFlags[i] = false;
}
Min = FVector::Min(Min, MyDensityField->IndexToVoxelPosition(FloodedIndex));
Max = FVector::Max(Max, MyDensityField->IndexToVoxelPosition(FloodedIndex));
}
void UMagicWand::InitMagicWandSelection()
UE::Geometry::FMarchingCubes MarchingCubes;
MarchingCubes.Bounds = UE::Geometry::TAxisAlignedBox3(Min, Max);
MarchingCubes.CubeSize = MarchingCubeSize == 0 ? MyDensityField->GetStep().X : MarchingCubeSize;
MarchingCubes.CancelF = [this]() {
return AbortMarchingCubes;
};
MarchingCubes.IsoValue = 0;
AbortMarchingCubes = false;
// Define the implicit function
MarchingCubes.Implicit = [this, Voxels](const FVector3d& Pos) {
const FVector PosConverted = FVector(Pos.X, Pos.Y, Pos.Z);
const int Index = MyDensityField->WorldPositionToIndex(PosConverted);
return Voxels.Contains(Index) ? 1 : -1;
};
MarchingCubes.bParallelCompute = true;
const UE::Geometry::FMeshShapeGenerator& Generator = MarchingCubes.Generate();
TArray<FVector3d> Vertices3d = Generator.Vertices;
TArray<UE::Geometry::FIndex3i> Triangles = Generator.Triangles;
TArray<FVector3f> Normals3F = Generator.Normals;
// Convert FVector3d to FVector
TArray<FVector> Vertices;
Vertices.Reserve(Generator.Vertices.Num());
for (const FVector3d& Vertex : Vertices3d)
{
const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation();
MyDensityField = MyPointCloud->MyDensityField;
Vertices.Add(FVector(Vertex.X, Vertex.Y, Vertex.Z));
}
// Convert the world position of the selection object to the local position relative to the point cloud
ProceduralMesh->ClearAllMeshSections();
World = GetWorld();
// Convert FIndex3i to int32
TArray<int32> Indices;
Indices.Reserve(Generator.Triangles.Num() * 3);
for (const UE::Geometry::FIndex3i& Triangle : Triangles)
{
Indices.Add(Triangle.A);
Indices.Add(Triangle.B);
Indices.Add(Triangle.C);
}
AbortMarchingCubes = true;
//AccumulatedTime = 0.0f;
// Convert FVector3f to FVector
TArray<FVector> Normals;
Normals.Reserve(Generator.Normals.Num());
for (const FVector3f& Normal : Normals3F)
{
Normals.Add(FVector(Normal.X, Normal.Y, Normal.Z));
}
void UMagicWand::SelectParticles(const FVector& InputPosition)
TArray<FColor> VertexColors;
VertexColors.Reserve(Vertices.Num());
for (int32 i = 0; i < Vertices.Num(); ++i)
{
if (AccumulatedTime >= 1 / EvaluationsPerSecond)
VertexColors.Add(FColor::Green);
}
AsyncTask(ENamedThreads::Type::GameThread, [this, Vertices, Indices, Normals, VertexColors]()
{
AccumulatedTime = -10000;
FScopeLock MeshLock(&ProceduralMeshGuard);
ProceduralMesh->CreateMeshSection(0, Vertices, Indices, Normals, TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false);
ProceduralMesh->SetVisibility(true);
AccumulatedTime.Store(0);
IsMarchingCubesRunning = false;
});
});
}
// INPUT HANDLING
UE_LOG(LogTemp, Warning, TEXT("Input recognized!"));
AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this]()
void UMagicWand::HandleMetaSelectReleased(const FInputActionInstance& Instance)
{
Super::HandleMetaSelectReleased(Instance);
const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation();
const FVector SelectionLocalPosition = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(SelectionWorldPosition);
PerformMagicWandSelection(SelectionLocalPosition);
ProximityThreshold = FMath::Clamp(FVector::Dist(SelectionStartPosition, SelectionLocalPosition) / 10, 0.1, 10);
InitMagicWandSelection();
//UE_LOG(LogTemp, Warning, TEXT("Calculations done!"));
AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this, &SelectionLocalPosition]()
{
PerformMagicWandSelection(SelectionStartPosition);
});
}
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);
FScopeLock Lock(&ThreadNumberLock);
AbortMagicWand.Store(true);
//deselect all particles
for (int32 i = 0; i < MyPointCloud->SelectionFlags.Num(); ++i)
{
MyPointCloud->SelectionFlags[i] = false;
}
}
// MAGIC WAND SELECTION
void UMagicWand::InitMagicWandSelection()
{
ProceduralMesh->ClearAllMeshSections();
AbortMarchingCubes = true;
if(AccumulatedTime.Load() >= 0) AccumulatedTime.Store(1 / EvaluationsPerSecond);
AbortMagicWand.Store(false);
}
void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition)
{
if (MyPointCloud->SelectionFlags.Num() != MyPointCloud->PositionVectors.Num())
{
UE_LOG(LogTemp, Warning, TEXT("PerformMagicWandSelection: Positions and SelectionFlags array sizes do not match."));
UE_LOG(LogTemp, Error, TEXT("PerformMagicWandSelection: Positions and SelectionFlags array sizes do not match."));
return;
}
UE_LOG(LogTemp, Warning, TEXT("Starting Selection!"));
//UE_LOG(LogTemp, Warning, TEXT("Starting MagicWand Selection!"));
//UE_LOG(LogTemp, Warning, TEXT("Looking for Seed Index:"));
// 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)
{
ExpandSelectionFromPointIndex(SeedIndex);
}else
{
AccumulatedTime.Store( 0);
}
}
void UMagicWand::FindSeedIndex(const FVector& InputPosition, const int32 InputVoxelIndex, int32& SeedIndex) const
{
TArray<int32> Neighbors = MyDensityField->IndexToVoxelNeighbors(InputVoxelIndex);
Neighbors.Add(InputVoxelIndex);
int32 SeedIndex = INDEX_NONE;
float MinDistance = FLT_MAX;
SeedIndex = INDEX_NONE;
float MinDistance = FLT_MAX;
for(int NeighborDistance = 0; NeighborDistance < 3; ++NeighborDistance)
for(int NeighborDistance = 0; NeighborDistance < 4; ++NeighborDistance)
{
const int NumNeighbors = Neighbors.Num();
......@@ -167,59 +306,64 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition)
}
}
}
}
if (SeedIndex != INDEX_NONE)
void UMagicWand::ExpandSelectionFromPointIndex(const int32 SeedIndex)
{
//const FVector WorldPos = MyPointCloud->PointCloudVisualizer->GetComponentTransform().TransformPosition(MyPointCloud->PositionVectors[SeedIndex]);
//DrawDebugSphere(World, WorldPos, 0.1f, 20, FColor::Green, false, 1, 0, 1.0f);
//Expand selection from the seed
ExpandSelection(SeedIndex);
}else
{
AccumulatedTime = 0;
}
FScopeLock Lock(&ThreadNumberLock);
NumberThreads.Increment();
}
void UMagicWand::ExpandSelection(const int32 SeedIndex)
{
UE_LOG(LogTemp, Warning, TEXT("Expanding!"));
TQueue<int32> ToProcess;
ToProcess.Enqueue(SeedIndex);
SelectedClusterIndices.Add(SeedIndex);
TQueue<int32>* ProcessQueue = new TQueue<int32>{};
ProcessQueue->Enqueue(SeedIndex);
MyPointCloud->SelectionFlags[SeedIndex] = true;
const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold;
TArray<int> Indices;
TArray<FVector> Data;
int NumberToProcess = 0;
while (!ToProcess.IsEmpty())
while (!ProcessQueue->IsEmpty() && !AbortMagicWand.Load())
{
int32 CurrentQueuePointIndex;
ToProcess.Dequeue(CurrentQueuePointIndex);
if(NumberToProcess > 1000 && NumberThreads.GetValue() < MaxThreadCount) CreateNewExpansionThread(ProcessQueue, NumberToProcess);
int32 CurrentQueuePointIndex;
ProcessQueue->Dequeue(CurrentQueuePointIndex);
const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
Indices.Empty();
Data.Empty();
ExpandThroughNeighborsInRange(ProcessQueue, SquaredProximityThreshold, NumberToProcess, CurrentQueuePointPosition);
NumberToProcess--;
}
UKdtreeBPLibrary::CollectFromKdtree(MyPointCloud->MyKdTree, CurrentQueuePointPosition, MyPointCloud->InfluenceRadius, Indices, Data);
AbortSelection();
}
for(int i = 0; i < Indices.Num(); ++i)
void UMagicWand::ExpandSelectionFromPointIndexQueue(TQueue<int32>* ProcessQueue)
{
{
const int CurrentPointComparisonIndex = Indices[i];
FScopeLock Lock(&ThreadNumberLock);
NumberThreads.Increment();
}
//UE_LOG(LogTemp, Warning, TEXT("Opened New Thread! Number of Threads now: %d"), NumberThreads.GetValue());
const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold;
int NumberToProcess = 0;
if(MyPointCloud->SelectionFlags[CurrentPointComparisonIndex])
while (!ProcessQueue->IsEmpty() && !AbortMagicWand.Load())
{
continue;
if(NumberToProcess > 1000 && NumberThreads.GetValue() < MaxThreadCount) CreateNewExpansionThread(ProcessQueue, NumberToProcess);
int32 CurrentQueuePointIndex;
ProcessQueue->Dequeue(CurrentQueuePointIndex);
const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
ExpandThroughNeighborsInRange(ProcessQueue, SquaredProximityThreshold, NumberToProcess, CurrentQueuePointPosition);
NumberToProcess--;
}
ToProcess.Enqueue(CurrentPointComparisonIndex);
MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true;
AbortSelection();
}
/*
void UMagicWand::ExpandThroughNeighborsInRange(TQueue<int32>* ProcessQueue, const float SquaredProximityThreshold, int& NumberToProcess, const FVector& CurrentQueuePointPosition) const
{
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));
......@@ -227,24 +371,15 @@ void UMagicWand::ExpandSelection(const int32 SeedIndex)
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);
for (int32 Z = StartZ; Z <= EndZ; ++Z)
{
for (int32 Y = StartY; Y <= EndY; ++Y)
{
for (int32 X = StartX; X <= EndX; ++X)
{
if(AbortMagicWand.Load()) return;
const int32 CurrentVoxelComparisonIndex = MyDensityField->GridPositionToIndex(X, Y, Z);
/*
if(!MyDensityField->IsValidIndex(CurrentVoxelComparisonIndex))
{
continue;
......@@ -264,149 +399,72 @@ void UMagicWand::ExpandSelection(const int32 SeedIndex)
if (SquaredDistance <= SquaredProximityThreshold)
{
ToProcess.Enqueue(CurrentPointComparisonIndex);
//SelectedClusterIndices.Add(CurrentPointComparisonIndex);
ProcessQueue->Enqueue(CurrentPointComparisonIndex);
NumberToProcess++;
if(AbortMagicWand.Load()) return;
MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true;
}
}
}
}
}*/
}
UE_LOG(LogTemp, Warning, TEXT("Calculations done!"));
AccumulatedTime = 0;
}
void UMagicWand::GenerateVoxelMeshWithCubes(const TArray<int32> Voxels) const
void UMagicWand::AbortSelection()
{
TArray<FVector> Vertices;
TArray<int32> Triangles;
TArray<FColor> VertexColors;
NumberThreads.Decrement();
// Generate cube vertices and triangles for each voxel
for (const int32 VoxelIndex : Voxels)
//UE_LOG(LogTemp, Warning, TEXT("Thread Closed! Number of Threads now: %d"), NumberThreads.GetValue());
if(NumberThreads.GetValue() == 0)
{
if(!MyDensityField->IsValidIndex(VoxelIndex))
AccumulatedTime.Store(0);
//AbortMagicWand.Store(false);
//UE_LOG(LogTemp, Warning, TEXT("Aborted!"));
}else if(NumberThreads.GetValue() < 0)
{
continue;
}
TArray<FVector> VoxelCorners = MyDensityField->IndexToVoxelCornersWorld(VoxelIndex);
// Add vertices for the voxel
const int32 BaseIndex = Vertices.Num();
Vertices.Append(VoxelCorners);
// Define the triangles (12 triangles for 6 faces of the cube)
// Each face of the cube has 2 triangles (6 faces * 2 triangles per face = 12 triangles)
Triangles.Append({
BaseIndex + 0, BaseIndex + 1, BaseIndex + 2, BaseIndex + 0, BaseIndex + 2, BaseIndex + 3, // Bottom face
BaseIndex + 4, BaseIndex + 6, BaseIndex + 5, BaseIndex + 4, BaseIndex + 7, BaseIndex + 6, // Top face
BaseIndex + 0, BaseIndex + 4, BaseIndex + 1, BaseIndex + 1, BaseIndex + 4, BaseIndex + 5, // Front face
BaseIndex + 1, BaseIndex + 5, BaseIndex + 2, BaseIndex + 2, BaseIndex + 5, BaseIndex + 6, // Right face
BaseIndex + 2, BaseIndex + 6, BaseIndex + 3, BaseIndex + 3, BaseIndex + 6, BaseIndex + 7, // Back face
BaseIndex + 3, BaseIndex + 7, BaseIndex + 0, BaseIndex + 0, BaseIndex + 7, BaseIndex + 4 // Left face
});
// Add red color for each corner vertex
for (int32 i = 0; i < 8; ++i)
{
VertexColors.Add(FColor::Green);
}
UE_LOG(LogTemp, Error, TEXT("More Threads closed than opened!"));
}
// Create the mesh section
AsyncTask(ENamedThreads::Type::GameThread, [this, Vertices, Triangles, VertexColors]()
{
//CreateMeshSections(Vertices, Triangles, VertexColors, 1000);
ProceduralMesh->CreateMeshSection(0, Vertices, Triangles, TArray<FVector>(), TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false);
ProceduralMesh->SetVisibility(true);
});
}
void UMagicWand::GenerateVoxelMeshSmooth(const TArray<int32> Voxels)
void UMagicWand::CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& NumberToProcess)
{
if(IsMarchingCubesRunning)
return;
TQueue<int32>* TempQueue = new TQueue<int32>{};
const int NumberRemove = NumberToProcess / 2;
IsMarchingCubesRunning = true;
FScopeLock Lock(&ProceduralMeshGuard);
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [this, Voxels]()
for(int i = 0; i < NumberRemove; ++i)
{
FVector Min(FLT_MAX, FLT_MAX, FLT_MAX);
FVector Max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
int32 CurrentQueuePointIndex;
ProcessQueue->Dequeue(CurrentQueuePointIndex);
NumberToProcess--;
TempQueue->Enqueue(CurrentQueuePointIndex);
}
for(const int FloodedIndex : Voxels)
AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this, TempQueue]()
{
Min = FVector::Min(Min, MyDensityField->IndexToVoxelPosition(FloodedIndex));
Max = FVector::Max(Max, MyDensityField->IndexToVoxelPosition(FloodedIndex));
ExpandSelectionFromPointIndexQueue(TempQueue);
});
}
UE::Geometry::FMarchingCubes MarchingCubes;
MarchingCubes.Bounds = UE::Geometry::TAxisAlignedBox3(Min, Max);
MarchingCubes.CubeSize = MarchingCubeSize == 0 ? MyDensityField->GetStep().X : MarchingCubeSize;
MarchingCubes.CancelF = [this]() {
return AbortMarchingCubes;
};
MarchingCubes.IsoValue = 0;
AbortMarchingCubes = false;
// Define the implicit function
MarchingCubes.Implicit = [this, Voxels](const FVector3d& Pos) {
const FVector PosConverted = FVector(Pos.X, Pos.Y, Pos.Z);
const int Index = MyDensityField->WorldPositionToIndex(PosConverted);
return Voxels.Contains(Index) ? 1 : -1;
};
MarchingCubes.bParallelCompute = true;
const UE::Geometry::FMeshShapeGenerator& Generator = MarchingCubes.Generate();
TArray<FVector3d> Vertices3d = Generator.Vertices;
TArray<UE::Geometry::FIndex3i> Triangles = Generator.Triangles;
TArray<FVector3f> Normals3F = Generator.Normals;
// TICK
// Convert FVector3d to FVector
TArray<FVector> Vertices;
Vertices.Reserve(Generator.Vertices.Num());
for (const FVector3d& Vertex : Vertices3d)
void UMagicWand::TickComponent(const float DeltaTime, const ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Vertices.Add(FVector(Vertex.X, Vertex.Y, Vertex.Z));
}
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// Convert FIndex3i to int32
TArray<int32> Indices;
Indices.Reserve(Generator.Triangles.Num() * 3);
for (const UE::Geometry::FIndex3i& Triangle : Triangles)
{
Indices.Add(Triangle.A);
Indices.Add(Triangle.B);
Indices.Add(Triangle.C);
/*
AccumulatedTime.Store(AccumulatedTime.Load() + DeltaTime);
ProceduralMesh->SetVisibility(Select);*/
}
// Convert FVector3f to FVector
TArray<FVector> Normals;
Normals.Reserve(Generator.Normals.Num());
for (const FVector3f& Normal : Normals3F)
void UMagicWand::SelectParticles(const FVector& InputPosition)
{
Normals.Add(FVector(Normal.X, Normal.Y, Normal.Z));
}
TArray<FColor> VertexColors;
VertexColors.Reserve(Vertices.Num());
for (int32 i = 0; i < Vertices.Num(); ++i)
if (AccumulatedTime.Load() >= 1 / EvaluationsPerSecond)
{
VertexColors.Add(FColor::Green);
AccumulatedTime.Store(FLT_MIN);
}
AsyncTask(ENamedThreads::Type::GameThread, [this, Vertices, Indices, Normals, VertexColors]()
{
FScopeLock MeshLock(&ProceduralMeshGuard);
ProceduralMesh->CreateMeshSection(0, Vertices, Indices, Normals, TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false);
ProceduralMesh->SetVisibility(true);
AccumulatedTime = 0.0f;
IsMarchingCubesRunning = false;
});
});
const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation();
DrawDebugLine(World, SelectionWorldPosition, MyPointCloud->PointCloudVisualizer->GetComponentTransform().TransformPosition(SelectionStartPosition), FColor::Red, false, 0, 0, 0.1f);
}
\ No newline at end of file
#pragma once
#include "CoreMinimal.h"
#include "ProceduralMeshComponent.h"
#include "MetaCastBaseline.h"
#include "Generators/MarchingCubes.h"
#include "Templates/Atomic.h"
#include "MagicWand.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
......@@ -12,48 +12,68 @@ class UMagicWand : public UMetaCastBaseline
{
GENERATED_BODY()
// INTERNAL
TAtomic<bool> AbortMagicWand = false;
FDensityField* MyDensityField;
UPROPERTY()
UWorld* World;
bool IsMarchingCubesRunning = false;
bool AbortMarchingCubes = false;
// Critical section to protect shared variables
FThreadSafeCounter NumberThreads = 0;
mutable FCriticalSection ProceduralMeshGuard;
mutable FCriticalSection ThreadNumberLock;
UPROPERTY()
UProceduralMeshComponent* ProceduralMesh;
UPROPERTY(EditAnywhere)
UMaterialInterface* SelectionVolumeMat;
TArray<int32> FloodedIndices;
UPROPERTY()
UWorld* World;
TAtomic<float> AccumulatedTime = 0.0;
FVector SelectionStartPosition;
// USER EXPORTED
UPROPERTY(EditAnywhere)
float MarchingCubeSize = 0;
UPROPERTY(EditAnywhere)
int EvaluationsPerSecond = 10;
UPROPERTY(EditAnywhere)
float AccumulatedTime = 0.0;
UPROPERTY(EditAnywhere)
float ProximityThreshold = 0.1f;
TArray<int32> SelectedClusterIndices;
UPROPERTY(EditAnywhere)
UMaterialInterface* SelectionVolumeMat;
UPROPERTY(EditAnywhere)
int MaxThreadCount = 100;
public:
UMagicWand();
// INITIALIZATION
UMagicWand();
virtual void BeginPlay() override;
void InitReferences();
void InitProceduralMesh() const;
virtual void SelectParticles(const FVector& InputPosition) override;
virtual void EraseParticles(const FVector& InputPosition) override;
// INPUT HANDLING
virtual void HandleMetaSelectReleased(const FInputActionInstance& Instance) override;
virtual void HandleMetaSelectPressed(const FInputActionInstance& Instance) override;
virtual void HandleMetaEraseReleased(const FInputActionInstance& Instance) override;
void InitMagicWandSelection();
virtual void EraseParticles(const FVector& InputPosition) override;
// VISUALIZATION
void GenerateVoxelMeshWithCubes(const TArray<int32> Voxels) const;
void GenerateVoxelMeshSmooth(const TArray<int32> Voxels);
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
// MAGIC WAND SELECTION
void InitMagicWandSelection();
void FindSeedIndex(const FVector& InputPosition, int32 InputVoxelIndex, int32& SeedIndex) const;
void PerformMagicWandSelection(const FVector& InputPosition);
void ExpandSelection(int32 SeedIndex);
void ExpandSelectionFromPointIndex(int32 SeedIndex);
void ExpandSelectionFromPointIndexQueue(TQueue<int32>* ProcessQueue);
void ExpandThroughNeighborsInRange(TQueue<int32>* ProcessQueue, const float SquaredProximityThreshold, int& NumberToProcess, const FVector& CurrentQueuePointPosition) const;
void AbortSelection();
void CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& NumberToProcess);
// TICK
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
virtual void SelectParticles(const FVector& InputPosition) override;
};
\ No newline at end of file
//The following code is modified from "unity-marching-cubes-gpu" by Pavel Kouřil. Original at: "https://github.com/pavelkouril/unity-marching-cubes-gpu"
/**
* Lookup tables and algorithm taken from "Polygonising a scalar field" by Paul Bourke
*
* Original at: http://paulbourke.net/geometry/polygonise/
*/
#pragma kernel MarchingCubes
Texture3D<float4> _posTexture;
Texture3D<float4> _densityTexture;
Texture3D<float4> _mcFlagTexture;
float _isoLevel;
int _gridSize;
struct Vertex
{
float3 vPosition;
float3 vNormal;
};
struct Triangle
{
Vertex v[3];
};
AppendStructuredBuffer<Triangle> triangleRW;
SamplerState myLinearClampSampler;
static const int edgeTable[256] = {
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
static const int triTable[256][16] =
{ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
{ 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },
{ 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },
{ 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 },
{ 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },
{ 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },
{ 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },
{ 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 },
{ 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },
{ 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 },
{ 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
{ 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 },
{ 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 },
{ 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },
{ 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 },
{ 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },
{ 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },
{ 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
{ 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 },
{ 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
{ 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },
{ 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 },
{ 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },
{ 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
{ 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 },
{ 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },
{ 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
{ 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },
{ 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 },
{ 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },
{ 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
{ 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },
{ 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },
{ 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
{ 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },
{ 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 },
{ 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
{ 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },
{ 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 },
{ 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 },
{ 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },
{ 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 },
{ 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },
{ 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 },
{ 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },
{ 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 },
{ 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 },
{ 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },
{ 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },
{ 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },
{ 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 },
{ 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },
{ 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },
{ 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 },
{ 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },
{ 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 },
{ 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 },
{ 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 },
{ 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },
{ 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },
{ 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 },
{ 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },
{ 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },
{ 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 },
{ 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },
{ 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 },
{ 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },
{ 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 },
{ 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },
{ 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },
{ 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 },
{ 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 },
{ 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },
{ 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 },
{ 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },
{ 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 },
{ 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 },
{ 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 },
{ 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },
{ 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },
{ 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },
{ 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 },
{ 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },
{ 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },
{ 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 },
{ 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },
{ 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },
{ 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 },
{ 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },
{ 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 },
{ 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },
{ 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 },
{ 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 },
{ 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 },
{ 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },
{ 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 },
{ 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },
{ 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 },
{ 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },
{ 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 },
{ 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },
{ 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },
{ 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 },
{ 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },
{ 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 },
{ 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },
{ 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },
{ 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 },
{ 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };
float SampleData(int3 pos) { // read the val data from the texture
return _densityTexture.Load(int4(pos, 0)).x;
}
float3 SamplePosData(int3 pos) { // read the pos data from the texture
return float3(_posTexture.Load(int4(pos, 0)).x, _posTexture.Load(int4(pos, 0)).y, _posTexture.Load(int4(pos, 0)).z);
}
float SampleFlagData(int3 pos) { // read the pos data from the texture
return _mcFlagTexture.Load(int4(pos, 0)).x;
}
float SampleLinear(float3 p)
{
// need to mitigate the offset in p[x], so +float3(0.5) to be in [0;1] range
return _densityTexture.SampleLevel(myLinearClampSampler, p + float3(0.5, 0.5, 0.5), 0).x;
}
float3 VertexInterp(float3 p1, float3 p2, float valp1, float valp2)
{
return lerp(p1, p2, (_isoLevel - valp1) / (valp2 - valp1));
}
float3 CalculateGradient(float3 p)
{
float ratio = 1.0 / (_gridSize );
return float3(
SampleLinear(p - float3(1.0, 0.0, 0.0) * ratio)
- SampleLinear(p + float3(1.0, 0.0, 0.0) * ratio),
SampleLinear(p - float3(0.0, 1.0, 0.0) * ratio)
- SampleLinear(p + float3(0.0, 1.0, 0.0) * ratio),
SampleLinear(p - float3(0.0, 0.0, 1.0) * ratio)
- SampleLinear(p + float3(0.0, 0.0, 1.0) * ratio)
);
}
[numthreads(8, 8, 8)]
void MarchingCubes(uint3 threadId : SV_DispatchThreadID)
{
if (SampleFlagData(threadId) == 0)
return;
float3 p[8] = {
SamplePosData(threadId + int3(0, 0, 1)),
SamplePosData(threadId + int3(1, 0, 1)),
SamplePosData(threadId + int3(1, 0, 0)),
SamplePosData(threadId + int3(0, 0, 0)),
SamplePosData(threadId + int3(0, 1, 1)),
SamplePosData(threadId + int3(1, 1, 1)),
SamplePosData(threadId + int3(1, 1, 0)),
SamplePosData(threadId + int3(0, 1, 0))
};
float val[8] = {
SampleData(threadId + int3(0, 0, 1)),
SampleData(threadId + int3(1, 0, 1)),
SampleData(threadId + int3(1, 0, 0)),
SampleData(threadId + int3(0, 0, 0)),
SampleData(threadId + int3(0, 1, 1)),
SampleData(threadId + int3(1, 1, 1)),
SampleData(threadId + int3(1, 1, 0)),
SampleData(threadId + int3(0, 1, 0))
};
int cubeIndex = 0;
if (val[0] < _isoLevel) cubeIndex |= 1;
if (val[1] < _isoLevel) cubeIndex |= 2;
if (val[2] < _isoLevel) cubeIndex |= 4;
if (val[3] < _isoLevel) cubeIndex |= 8;
if (val[4] < _isoLevel) cubeIndex |= 16;
if (val[5] < _isoLevel) cubeIndex |= 32;
if (val[6] < _isoLevel) cubeIndex |= 64;
if (val[7] < _isoLevel) cubeIndex |= 128;
float3 vertlist[12];
if (edgeTable[cubeIndex] != 0)
{
if (edgeTable[cubeIndex] & 1)
vertlist[0] = VertexInterp(p[0], p[1], val[0], val[1]);
if (edgeTable[cubeIndex] & 2)
vertlist[1] = VertexInterp(p[1], p[2], val[1], val[2]);
if (edgeTable[cubeIndex] & 4)
vertlist[2] = VertexInterp(p[2], p[3], val[2], val[3]);
if (edgeTable[cubeIndex] & 8)
vertlist[3] = VertexInterp(p[3], p[0], val[3], val[0]);
if (edgeTable[cubeIndex] & 16)
vertlist[4] = VertexInterp(p[4], p[5], val[4], val[5]);
if (edgeTable[cubeIndex] & 32)
vertlist[5] = VertexInterp(p[5], p[6], val[5], val[6]);
if (edgeTable[cubeIndex] & 64)
vertlist[6] = VertexInterp(p[6], p[7], val[6], val[7]);
if (edgeTable[cubeIndex] & 128)
vertlist[7] = VertexInterp(p[7], p[4], val[7], val[4]);
if (edgeTable[cubeIndex] & 256)
vertlist[8] = VertexInterp(p[0], p[4], val[0], val[4]);
if (edgeTable[cubeIndex] & 512)
vertlist[9] = VertexInterp(p[1], p[5], val[1], val[5]);
if (edgeTable[cubeIndex] & 1024)
vertlist[10] = VertexInterp(p[2], p[6], val[2], val[6]);
if (edgeTable[cubeIndex] & 2048)
vertlist[11] = VertexInterp(p[3], p[7], val[3], val[7]);
for (int i = 0; triTable[cubeIndex][i] != -1; i += 3) {
Triangle t;
Vertex v0;
Vertex v1;
Vertex v2;
v0.vPosition = vertlist[triTable[cubeIndex][i]];
v1.vPosition = vertlist[triTable[cubeIndex][i + 1]];
v2.vPosition = vertlist[triTable[cubeIndex][i + 2]];
v0.vNormal = normalize(CalculateGradient(v0.vPosition));
v1.vNormal = normalize(CalculateGradient(v1.vPosition));
v2.vNormal = normalize(CalculateGradient(v2.vPosition));
t.v[0] = v0;
t.v[1] = v1;
t.v[2] = v2;
triangleRW.Append(t);
}
}
}
\ No newline at end of file
......@@ -10,6 +10,16 @@ UMetaCastBaseline::UMetaCastBaseline() :
PrimaryComponentTick.bCanEverTick = true;
}
void UMetaCastBaseline::InitLeftHand()
{
//check if left hand is assigned otherwise assign it to self
if(!LeftHandComponent)
{
UE_LOG(LogTemp, Warning, TEXT("Left Hand not assigned. Please assign in Blueprint => Defaulting to self"));
LeftHandComponent = this;
}
}
// Called when the game starts
void UMetaCastBaseline::BeginPlay()
{
......@@ -18,13 +28,7 @@ void UMetaCastBaseline::BeginPlay()
InitPointCloudReference();
InitInputBindings();
InitSelectionObject();
//check if left hand is assigned otherwise assign it to self
if(!LeftHandComponent)
{
UE_LOG(LogTemp, Warning, TEXT("Left Hand not assigned. Please assign in Blueprint => Defaulting to self"));
LeftHandComponent = this;
}
InitLeftHand();
}
void UMetaCastBaseline::InitPointCloudReference()
......
......@@ -60,6 +60,7 @@ public:
// Sets default values for this component's properties
UMetaCastBaseline();
void InitLeftHand();
void InitInputBindings();
virtual void HandleMetaSelectPressed(const FInputActionInstance& Instance);
virtual void HandleMetaErasePressed(const FInputActionInstance& Instance);
......
......@@ -91,7 +91,7 @@ void APointCloud::SetupDensityFieldFromPointCloud() const
{
UE_LOG(LogTemp, Log, TEXT("Initializing DensityField!"));
const FIntVector AxisNumbers(100, 100, 100);
const FIntVector AxisNumbers(200, 200, 200);
MyDensityField->InitializeDensityField(this, MinBounds, MaxBounds, AxisNumbers);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment