Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Fill out your copyright notice in the Description page of Project Settings.
- #include "Voxel/VoxelTerrainActor.h"
- #include "DrawDebugHelpers.h"
- #include "ProceduralMeshComponent.h"
- #include "KismetProceduralMeshLibrary.h"
- #include "Components/TextRenderComponent.h"
- // Sets default values
- AVoxelTerrainActor::AVoxelTerrainActor()
- {
- // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
- PrimaryActorTick.bCanEverTick = true;
- ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("Procedural Mesh"));
- }
- // Called when the game starts or when spawned
- void AVoxelTerrainActor::BeginPlay()
- {
- Super::BeginPlay();
- Setup(1.0f);
- FTimerHandle H{ };
- GetWorldTimerManager().SetTimer(H, [this]()
- {
- RemoveVoxel(Chunks[0]);
- }, 1.0f / 1.0f, true);
- }
- void AVoxelTerrainActor::Setup(float Res)
- {
- #if !WITH_EDITOR
- this->Resolution = Res;
- #endif
- for (int i = 0; i < 1; i++)
- {
- auto& Chunk = Chunks.AddDefaulted_GetRef();
- Chunk.Extent = FVector2D(NumVoxelsXY * VoxelSize, NumVoxelsXY * VoxelSize);
- SetupChunk(Chunk);
- }
- }
- void AVoxelTerrainActor::SetupChunk(FChunk& Chunk)
- {
- for (float i = VoxelSize / 2 + Chunk.Origin.X; i < Chunk.Extent.X - Chunk.Origin.X; i += VoxelSize)
- for (float j = VoxelSize / 2 + Chunk.Origin.X; j < Chunk.Extent.Y - Chunk.Origin.Y; j += VoxelSize)
- {
- const float z = 15.0f;
- FVoxel V;
- V.Position = FVector(i, j, z);
- if (i == VoxelSize / 2 + Chunk.Origin.X)
- V.PositionFlags |= ESurroundingVoxels::NegX;
- if (i + VoxelSize >= Chunk.Origin.X + Chunk.Extent.X)
- V.PositionFlags |= ESurroundingVoxels::PosX;
- if (j == VoxelSize / 2 + Chunk.Origin.Y)
- V.PositionFlags |= ESurroundingVoxels::NegY;
- if (j + VoxelSize >= Chunk.Origin.Y + Chunk.Extent.Y)
- V.PositionFlags |= ESurroundingVoxels::PosY;
- V.PositionFlags |= ESurroundingVoxels::Bottom | ESurroundingVoxels::Top;
- Chunk.Voxels.Add(V.Position, V);
- }
- BuildChunk(Chunk);
- }
- void AVoxelTerrainActor::BuildChunk(FChunk& Chunk)
- {
- ProceduralMesh->ClearAllMeshSections();
- int Index = 0;
- for (auto& P : Chunk.Voxels)
- {
- auto& V = P.Value;
- V.MeshIndex = Index;
- Index++;
- TArray<FVector> Positions;
- TArray<int32> Indices;
- TArray<FVector2D> UVs;
- TArray<FVector> Normals;
- TArray<FProcMeshTangent> Tangents;
- // TOP
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- // BOTTOM
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- // POS X
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- // NEG X
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- // POS Y
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y + (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- // NEG Y
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X + (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(V.Position.X - (VoxelSize / 2), V.Position.Y - (VoxelSize / 2), V.Position.Z - (VoxelSize / 2)));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- if (V.PositionFlags & ESurroundingVoxels::Top)
- {
- Indices.Add(1);
- Indices.Add(0);
- Indices.Add(2);
- Indices.Add(1);
- Indices.Add(2);
- Indices.Add(3);
- }
- if (V.PositionFlags & ESurroundingVoxels::Bottom)
- {
- Indices.Add(4);
- Indices.Add(5);
- Indices.Add(6);
- Indices.Add(6);
- Indices.Add(5);
- Indices.Add(7);
- }
- if (V.PositionFlags & ESurroundingVoxels::PosX)
- {
- Indices.Add(8);
- Indices.Add(9);
- Indices.Add(10);
- Indices.Add(10);
- Indices.Add(9);
- Indices.Add(11);
- }
- if (V.PositionFlags & ESurroundingVoxels::NegX)
- {
- Indices.Add(13);
- Indices.Add(12);
- Indices.Add(14);
- Indices.Add(13);
- Indices.Add(14);
- Indices.Add(15);
- }
- if (V.PositionFlags & ESurroundingVoxels::PosY)
- {
- Indices.Add(16);
- Indices.Add(17);
- Indices.Add(18);
- Indices.Add(18);
- Indices.Add(17);
- Indices.Add(19);
- }
- if (V.PositionFlags & ESurroundingVoxels::NegY)
- {
- Indices.Add(21);
- Indices.Add(20);
- Indices.Add(22);
- Indices.Add(21);
- Indices.Add(22);
- Indices.Add(23);
- }
- UKismetProceduralMeshLibrary::CalculateTangentsForMesh(Positions, Indices, UVs, Normals, Tangents);
- ProceduralMesh->CreateMeshSection(V.MeshIndex, Positions, Indices, Normals, UVs, TArray<FColor>(), Tangents, true);
- if (Material)
- {
- ProceduralMesh->SetMaterial(V.MeshIndex, Material);
- }
- }
- }
- void AVoxelTerrainActor::BuildVoxel(FVoxel& Voxel)
- {
- ProceduralMesh->ClearMeshSection(Voxel.MeshIndex);
- TArray<FVector> Positions;
- TArray<int32> Indices;
- TArray<FVector2D> UVs;
- TArray<FVector> Normals;
- TArray<FProcMeshTangent> Tangents;
- // TOP
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- // BOTTOM
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- // POS X
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- // NEG X
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- // POS Y
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y + (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- // NEG Y
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z + (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X + (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- Positions.Add(FVector(Voxel.Position.X - (VoxelSize / 2), Voxel.Position.Y - (VoxelSize / 2), Voxel.Position.Z - (VoxelSize / 2)));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- UVs.Add(FVector2D(0, 0));
- UVs.Add(FVector2D(0, 1));
- UVs.Add(FVector2D(1, 0));
- UVs.Add(FVector2D(1, 1));
- if (Voxel.PositionFlags & ESurroundingVoxels::Top)
- {
- Indices.Add(1);
- Indices.Add(0);
- Indices.Add(2);
- Indices.Add(1);
- Indices.Add(2);
- Indices.Add(3);
- }
- if (Voxel.PositionFlags & ESurroundingVoxels::Bottom)
- {
- Indices.Add(4);
- Indices.Add(5);
- Indices.Add(6);
- Indices.Add(6);
- Indices.Add(5);
- Indices.Add(7);
- }
- if (Voxel.PositionFlags & ESurroundingVoxels::PosX)
- {
- Indices.Add(8);
- Indices.Add(9);
- Indices.Add(10);
- Indices.Add(10);
- Indices.Add(9);
- Indices.Add(11);
- }
- if (Voxel.PositionFlags & ESurroundingVoxels::NegX)
- {
- Indices.Add(13);
- Indices.Add(12);
- Indices.Add(14);
- Indices.Add(13);
- Indices.Add(14);
- Indices.Add(15);
- }
- if (Voxel.PositionFlags & ESurroundingVoxels::PosY)
- {
- Indices.Add(16);
- Indices.Add(17);
- Indices.Add(18);
- Indices.Add(18);
- Indices.Add(17);
- Indices.Add(19);
- }
- if (Voxel.PositionFlags & ESurroundingVoxels::NegY)
- {
- Indices.Add(21);
- Indices.Add(20);
- Indices.Add(22);
- Indices.Add(21);
- Indices.Add(22);
- Indices.Add(23);
- }
- UKismetProceduralMeshLibrary::CalculateTangentsForMesh(Positions, Indices, UVs, Normals, Tangents);
- ProceduralMesh->CreateMeshSection(Voxel.MeshIndex, Positions, Indices, Normals, UVs, TArray<FColor>(), Tangents, true);
- if (Material)
- {
- ProceduralMesh->SetMaterial(Voxel.MeshIndex, Material);
- }
- }
- void AVoxelTerrainActor::RemoveVoxel(FChunk& Chunk)
- {
- TArray<FVector> VoxelPositions;
- Chunk.Voxels.GetKeys(VoxelPositions);
- auto P = VoxelPositions[0];
- auto& V = Chunk.Voxels[P];
- if (!(V.PositionFlags & ESurroundingVoxels::Top))
- {
- if (auto* FV = Chunk.Voxels.Find(FVector(P.X, P.Y, P.Z + VoxelSize)))
- {
- FV->PositionFlags |= ESurroundingVoxels::Bottom;
- BuildVoxel(*FV);
- }
- }
- if (!(V.PositionFlags & ESurroundingVoxels::Bottom))
- {
- if (auto* FV = Chunk.Voxels.Find(FVector(P.X, P.Y, P.Z - VoxelSize)))
- {
- FV->PositionFlags |= ESurroundingVoxels::Top;
- BuildVoxel(*FV);
- }
- }
- if (!(V.PositionFlags & ESurroundingVoxels::PosX))
- {
- if (auto* FV = Chunk.Voxels.Find(FVector(P.X + VoxelSize, P.Y, P.Z)))
- {
- FV->PositionFlags |= ESurroundingVoxels::NegX;
- BuildVoxel(*FV);
- }
- }
- if (!(V.PositionFlags & ESurroundingVoxels::NegX))
- {
- if (auto* FV = Chunk.Voxels.Find(FVector(P.X - VoxelSize, P.Y, P.Z)))
- {
- FV->PositionFlags |= ESurroundingVoxels::PosX;
- BuildVoxel(*FV);
- }
- }
- if (!(V.PositionFlags & ESurroundingVoxels::PosY))
- {
- if (auto* FV = Chunk.Voxels.Find(FVector(P.X, P.Y + VoxelSize, P.Z)))
- {
- FV->PositionFlags |= ESurroundingVoxels::NegY;
- BuildVoxel(*FV);
- }
- }
- if (!(V.PositionFlags & ESurroundingVoxels::NegY))
- {
- if (auto* FV = Chunk.Voxels.Find(FVector(P.X, P.Y - VoxelSize, P.Z)))
- {
- FV->PositionFlags |= ESurroundingVoxels::PosY;
- BuildVoxel(*FV);
- }
- }
- ProceduralMesh->ClearMeshSection(V.MeshIndex);
- Chunk.Voxels.Remove(P);
- //BuildChunk(Chunk);
- }
- // Called every frame
- void AVoxelTerrainActor::Tick(float DeltaTime)
- {
- Super::Tick(DeltaTime);
- }
Add Comment
Please, Sign In to add comment