My mesh doesn’t appear to be generating and I’m thinking it’s something with the way I’m creating triangles, but I can’t figure out where I’m screwing up.
This is the output. Definitely not what I was expecting:
LogTemp: Warning: Creating mesh for chunk : (8192) vert, (-908209720) triangles.
This is the main cpp:
#include "WorldChunk.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
AWorldChunk::AWorldChunk()
{
PrimaryActorTick.bCanEverTick = false;
if (!ProcMesh)
{
ProcMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProcMeshComponent"));
ProcMesh->SetupAttachment(RootComponent);
ProcMesh->SetVisibility(true);
}
}
// Called when the game starts
void AWorldChunk::BeginPlay()
{
Super::BeginPlay();
GenerateTerrain();
}
void AWorldChunk::GenerateTerrain()
{
UE_LOG(LogTemp, Warning, TEXT("Loading chunk..."));
// Create a grid of vertices
TArray<FVector> vertices;
for (int32 z = 0; z < gridSizeZ; z++)
{
for (int32 y = 0; y < gridSizeY; y++)
{
for (int32 x = 0; x < gridSizeX; x++)
{
// Calculate the world position of each vertex
FVector worldPos = GetActorLocation() + FVector(x * voxelSize, y * voxelSize, z * voxelSize);
float density = CalculateDensity(worldPos);
vertices.Add(worldPos + density * normal);
}
}
}
// Create triangles using Marching Cubes algorithm
TArray<int32> triangles;
for (int32 z = 0; z < gridSizeZ - 1; z++)
{
for (int32 y = 0; y < gridSizeY - 1; y++)
{
for (int32 x = 0; x < gridSizeX - 1; x++)
{
// Create a byte code to represent the density values of the corners
uint8 cubeIndex = 0;
for (int32 i = 0; i < 8; i++)
{
FVector cornerPos = vertices[GetIndex(x + edgeVertices[i][0],
y + edgeVertices[i][1],
z + edgeVertices[i][2])];
if (CalculateDensity(cornerPos) > 0)
cubeIndex |= (1 << i);
}
// Generate triangles for the current cube
for (int32 i = 0; triTable[cubeIndex][i] != -1; i += 3)
{
triangles.Add(GetIndex(x + triTable[cubeIndex][i],
y + triTable[cubeIndex][i + 1],
z + triTable[cubeIndex][i + 2]));
}
}
}
}
// Create mesh from generated vertices and triangles
if (ProcMesh && terrainMaterial)
{
FString vertcount = FString::FromInt(vertices.Num());
FString tricount = FString::FromInt(triangles.Num());
UE_LOG(LogTemp, Warning, TEXT("Creating mesh for chunk : (%s) vert, (%i) triangles."), *vertcount, *tricount);
ProcMesh->CreateMeshSection(0, vertices, triangles, TArray<FVector>(), TArray<FVector2D>(), TArray<FColor>(), TArray<FProcMeshTangent>(), true);
ProcMesh->SetMaterial(0, terrainMaterial);
}
}
int32 AWorldChunk::GetIndex(int32 x, int32 y, int32 z) const
{
return x + gridSizeX * (y + gridSizeY * z);
}
float AWorldChunk::CalculateDensity(const FVector& worldPos)
{
noiseScale = 0.1f; // Adjust the noise scale to control the level of detail
float noiseValue = FMath::PerlinNoise3D(worldPos * noiseScale);
threshold = 0.5f; // Adjust the threshold to control the terrain shape
return noiseValue - threshold;
}
const int32 AWorldChunk::edgeVertices[12][3] = {
{0, 1, 0}, {1, 1, 0}, {1, 0, 0}, {0, 0, 0},
{0, 1, 1}, {1, 1, 1}, {1, 0, 1}, {0, 0, 1},
{0, 0, 0}, {0, 1, 0}, {1, 1, 0}, {1, 0, 0}
};
const int32 AWorldChunk::triTable[256][16] = {
// Marching cubes table here... really big so I left this out for help post.
};
the .h file:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ProceduralMeshComponent.h"
#include "WorldChunk.generated.h"
UENUM(BlueprintType)
enum eBiomeType
{
Invalid,
Dirt,
Grass,
Water,
};
UCLASS(Abstract)
class WORLDGEN_API AWorldChunk : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
AWorldChunk();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
void GenerateTerrain();
int32 GetIndex(int32 x, int32 y, int32 z) const;
float CalculateDensity(const FVector& worldPos);// const;
static const int32 edgeVertices[12][3];
static const int32 triTable[256][16];
UPROPERTY(BlueprintReadOnly, Category = "Terrain")
UProceduralMeshComponent* ProcMesh;
UPROPERTY(EditAnywhere, Category = "Terrain")
UMaterialInterface* terrainMaterial; // The material used to render the terrain
UPROPERTY(EditAnywhere, Category = "Terrain")
int gridSizeZ = 32;
UPROPERTY(EditAnywhere, Category = "Terrain")
int gridSizeY = 16;
UPROPERTY(EditAnywhere, Category = "Terrain")
int gridSizeX = 16;
UPROPERTY(EditAnywhere, Category = "Terrain")
float threshold = 0.5f; // Adjust the threshold to control the terrain shape
UPROPERTY(EditAnywhere, Category = "Terrain")
float noiseScale = 0.1f; // Adjust the noise scale to control the level of detail
UPROPERTY(EditAnywhere, Category = "Terrain")
float voxelSize = 100.0f; // Set the default voxel size to 100 units
UPROPERTY(EditAnywhere, Category = "Terrain")
FVector normal = FVector(0.0f, 0.0f, 1.0f); // Set the default normal vector to (0, 0, 1)
};