So this is happening whenever the density is changing. As you can see with the yellow grid lines. I have no idea why this is happening and I have been working on this for a few weeks now so I am kind of losing hope, any help is greatly appreciated.
Here is my Marching Cubes component
#include "MarchingCubesMeshComponent.h"
void UMarchingCubesMeshComponent::MarchCube(
const FVector& position,
const TArray<float>& cornerValues,
TArray<FVector>& vertices,
TArray<int32>& triangles,
TArray<FVector>& normals)
{
// Calculate cube index - invert the comparison
int32 cubeIndex = 0;
for (int32 i = 0; i < 8; i++)
{
if (cornerValues[i] > SurfaceLevel) // Changed from < to >
{
cubeIndex |= 1 << i;
}
}
// Get edge flags for this cube configuration
int32 edgeFlags = CubeEdgeFlags[cubeIndex];
// If no edges are intersected, this cube is entirely inside or outside the surface
if (edgeFlags == 0)
{
return;
}
// Find the vertices where the surface intersects the cube
TArray<FVector> edgeVertices;
edgeVertices.SetNum(12);
// Scale factor to match your VoxelChunk's scale
const float VoxelScale = 100.0f; // This should match your VoxelSize
for (int32 i = 0; i < 12; i++)
{
if (edgeFlags & (1 << i))
{
int32 v1 = EdgeConnection[i][0];
int32 v2 = EdgeConnection[i][1];
// Create properly scaled vertices
FVector vertex1 = position + FVector(
VertexOffset[v1][0] * VoxelScale,
VertexOffset[v1][1] * VoxelScale,
VertexOffset[v1][2] * VoxelScale
);
FVector vertex2 = position + FVector(
VertexOffset[v2][0] * VoxelScale,
VertexOffset[v2][1] * VoxelScale,
VertexOffset[v2][2] * VoxelScale
);
edgeVertices[i] = GetOrCreateVertex(vertex1, vertex2, cornerValues[v1], cornerValues[v2]);
}
}
// Create triangles using the triangulation table
int32 vertOffset = vertices.Num();
for (int32 i = 0; TriangleConnectionTable[cubeIndex][i] != -1; i += 3)
{
// Add the three vertices for this triangle
vertices.Add(edgeVertices[TriangleConnectionTable[cubeIndex][i]]);
vertices.Add(edgeVertices[TriangleConnectionTable[cubeIndex][i + 1]]);
vertices.Add(edgeVertices[TriangleConnectionTable[cubeIndex][i + 2]]);
// Add this after each vertex is added in the triangle creation loop
for (int32 p = 0; TriangleConnectionTable[cubeIndex][p] != -1; p += 3)
{
// DrawDebugPoint(GetWorld(), vertices.Last(), 5.0f, FColor::Red, false, 5.0f);
// DrawDebugLine(GetWorld(), vertices.Last(), vertices.Last(1), FColor::Blue, false, 1000);
}
// Calculate and add the normal for this triangle
// Flip the edge order to reverse the normal direction
FVector edge1 = vertices.Last(2) - vertices.Last(1);
FVector edge2 = vertices.Last() - vertices.Last(1);
FVector normal = FVector::CrossProduct(edge1, edge2).GetSafeNormal();
normals.Add(normal);
// After calculating the normal in your triangle creation loop:
FVector triangleCenter = (vertices.Last() + vertices.Last(1) + vertices.Last(2)) / 3.0f;
DrawDebugLine(
GetWorld(),
triangleCenter,
triangleCenter + (normal * 50.0f), // Scale the normal for visibility
FColor::Red,
false,
500.0f,
0,
2.0f
);
// Add triangle indices
triangles.Add(vertOffset + i);
triangles.Add(vertOffset + i + 2);
triangles.Add(vertOffset + i + 1);
for (int32 t = 0; t < 12; t++)
{
if (edgeFlags & (1 << t))
{
int32 v1 = EdgeConnection[t][0];
int32 v2 = EdgeConnection[t][1];
FVector vert1 = position + FVector(
VertexOffset[v1][0] * VoxelScale,
VertexOffset[v1][1] * VoxelScale,
VertexOffset[v1][2] * VoxelScale
);
FVector vert2 = position + FVector(
VertexOffset[v2][0] * VoxelScale,
VertexOffset[v2][1] * VoxelScale,
VertexOffset[v2][2] * VoxelScale
);
DrawDebugLine(GetWorld(), vert1, vert2,
FColor::Yellow, false, 500.0f, 0, 2.0f);
}
}
// In the MarchCube function, after calculating cornerValues
for (int32 u = 0; u < 8; u++)
{
FVector cornerPos = position + FVector(
VertexOffset[u][0] * VoxelScale,
VertexOffset[u][1] * VoxelScale,
VertexOffset[u][2] * VoxelScale
);
FColor pointColor = cornerValues[u] > SurfaceLevel ? FColor::Green : FColor::Red;
DrawDebugPoint(GetWorld(), cornerPos, 10.0f, pointColor, false, 0.0f);
// Draw the actual value as text
FString valueText = FString::Printf(TEXT("%.2f"), cornerValues[u]);
DrawDebugString(GetWorld(), cornerPos, valueText, nullptr, FColor::White, 0.0f);
}
}
}
FVector UMarchingCubesMeshComponent::InterpolateVerts(const FVector& v1, const FVector& v2, float val1, float val2)
{
// Ensure we don't divide by zero
if (FMath::Abs(val1 - val2) < 0.0001f) return v1;
// Calculate interpolation factor - where along the edge should the vertex be
float t = (SurfaceLevel - val1) / (val2 - val1);
// Clamp t to prevent vertices from going outside the edge
t = FMath::Clamp(t, 0.0f, 1.0f);
// Precise linear interpolation
return FVector(
v1.X + (v2.X - v1.X) * t,
v1.Y + (v2.Y - v1.Y) * t,
v1.Z + (v2.Z - v1.Z) * t
);
}
FVector UMarchingCubesMeshComponent::GetOrCreateVertex(const FVector& pos1, const FVector& pos2, float val1, float val2)
{
// Sanitize input values first
val1 = FMath::IsNearlyZero(val1) ? 0.0f : val1;
val2 = FMath::IsNearlyZero(val2) ? 0.0f : val2;
// If the values are equal or very close, use midpoint
if (FMath::IsNearlyEqual(val1, val2, KINDA_SMALL_NUMBER))
{
return (pos1 + pos2) * 0.5f;
}
// Create grid-space key for caching
const float GridScale = 100.0f;
FIntVector gridPos1(
FMath::RoundToInt(pos1.X / GridScale),
FMath::RoundToInt(pos1.Y / GridScale),
FMath::RoundToInt(pos1.Z / GridScale)
);
FIntVector gridPos2(
FMath::RoundToInt(pos2.X / GridScale),
FMath::RoundToInt(pos2.Y / GridScale),
FMath::RoundToInt(pos2.Z / GridScale)
);
// Ensure consistent ordering
FIntVector minPos(
FMath::Min(gridPos1.X, gridPos2.X),
FMath::Min(gridPos1.Y, gridPos2.Y),
FMath::Min(gridPos1.Z, gridPos2.Z)
);
FIntVector maxPos(
FMath::Max(gridPos1.X, gridPos2.X),
FMath::Max(gridPos1.Y, gridPos2.Y),
FMath::Max(gridPos1.Z, gridPos2.Z)
);
// Create unique edge key
FString edgeKey = FString::Printf(TEXT("%d_%d_%d_%d_%d_%d"),
minPos.X, minPos.Y, minPos.Z,
maxPos.X, maxPos.Y, maxPos.Z);
// Check cache
if (FVector* cachedVertex = VertexCache.Find(edgeKey))
{
return *cachedVertex;
}
// Calculate interpolation factor
float t = (SurfaceLevel - val1) / (val2 - val1);
// Robust clamping
t = FMath::Clamp(t, 0.0f, 1.0f);
// Calculate interpolated position
FVector newVertex = pos1 + (pos2 - pos1) * t;
// Add debug visualization for high gradients
float densityDelta = FMath::Abs(val2 - val1);
if (densityDelta > 1.0f)
{
DrawDebugPoint(
GetWorld(),
newVertex,
5.0f,
FColor::Blue,
false,
5.0f
);
// Draw density values
DrawDebugString(
GetWorld(),
newVertex,
FString::Printf(TEXT("Δ=%.2f"), densityDelta),
nullptr,
FColor::White,
0.0f
);
}
// Cache and return
VertexCache.Add(edgeKey, newVertex);
return newVertex;
}
Please, any help would be so amazing and that you in advance if you can help.