实现基本 Cube 体素渲染

This commit is contained in:
_Redstone_c_ 2020-12-03 13:52:29 +08:00
commit 96e9af4438
26 changed files with 1694 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
Binaries
DerivedDataCache
Intermediate
Saved
Build
.vscode
.vs
*.VC.db
*.opensdf
*.opendb
*.sdf
*.sln
*.suo
*.xcodeproj
*.xcworkspace

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 zhaizhenbo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4
README.md Normal file
View File

@ -0,0 +1,4 @@
## UE4 Plugin: Voxel
[Voxel](http://gitblit.myredstone.top/summary/UE4-Plugins!Voxel.git) 是开发中的一个体素插件。
目前支持的 UE4 版本4.25.4

BIN
Resources/Icon128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,11 @@
#include "Blueprint/VoxelBlueprintLibrary.h"
#include "VoxelSubsystem.h"
#include "Kismet/GameplayStatics.h"
void UVoxelBlueprintLibrary::AddBlockType(const UObject* WorldContextObject, const FName& Name, const FVoxelBlockType& BlockType)
{
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject);
UVoxelSubsystem* LockstepSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>();
LockstepSubsystem->BlockTypes.Add(Name, BlockType);
}

View File

@ -0,0 +1,20 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Voxel.h"
#define LOCTEXT_NAMESPACE "FVoxelModule"
void FVoxelModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}
void FVoxelModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FVoxelModule, Voxel)

View File

@ -0,0 +1,11 @@
#include "VoxelAgentInterface.h"
FIntVector IVoxelAgentInterface::GetAgentLocation_Implementation() const
{
return FIntVector(0);
}
FVector IVoxelAgentInterface::GetAgentPartialLocation_Implementation() const
{
return FVector(0.0f);
}

View File

@ -0,0 +1,7 @@
#include "VoxelBlock.h"
#include "VoxelWorld.h"
const FVoxelBlock FVoxelBlock::InvalidBlock = FVoxelBlock(NAME_None);
const FVoxelBlockType FVoxelBlockType::InvalidBlockType = FVoxelBlockType(EVoxelBlockShape::Invalid);

View File

@ -0,0 +1,323 @@
#include "VoxelChunk.h"
#include "VoxelLog.h"
#include "VoxelWorld.h"
#include "VoxelSubsystem.h"
#include "ProceduralMeshComponent.h"
#include "KismetProceduralMeshLibrary.h"
AVoxelChunk::AVoxelChunk(const class FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
MeshComponents.SetNum(16);
for (int32 i = 0; i < 16; ++i)
{
FString ComponentName = FString::Printf(TEXT("MeshComponent_%d"), i);
MeshComponents[i] = CreateDefaultSubobject<UProceduralMeshComponent>(FName(ComponentName));
MeshComponents[i]->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
}
FlushMeshFlags = -1;
}
void AVoxelChunk::BeginPlay()
{
UGameInstance* GameInstance = GetGameInstance();
VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>();
}
const FVoxelBlock & AVoxelChunk::GetBlockByRelativeLocation(const FIntVector & Location) const
{
checkCode(
if (!FMath::IsWithin(Location.X, 0, 16)
|| !FMath::IsWithin(Location.Y, 0, 16)
|| !FMath::IsWithin(Location.Z, 0, 256))
{
UE_LOG(LogVoxel, Warning, TEXT("The Block %d, %d, %d Is Invalid In Chunk %d, %d"), Location.X, Location.Y, Location.Z, ChunkLocation.X, ChunkLocation.Y);
return FVoxelBlock::InvalidBlock;
}
);
return Blocks[Location.X][Location.Y][Location.Z];
}
void AVoxelChunk::SetBlockByRelativeLocation(const FIntVector& Location, const FVoxelBlock& NewBlock)
{
checkCode(
if (!FMath::IsWithin(Location.X, 0, 16)
|| !FMath::IsWithin(Location.Y, 0, 16)
|| !FMath::IsWithin(Location.Z, 0, 256))
{
UE_LOG(LogVoxel, Warning, TEXT("The Block %d, %d, %d Is Invalid In Chunk %d, %d"), Location.X, Location.Y, Location.Z, ChunkLocation.X, ChunkLocation.Y);
return;
}
);
Blocks[Location.X][Location.Y][Location.Z] = NewBlock;
FlushMeshFlags |= 1 << (Location.Z / 16);
if (Location.Z % 16 == 0 && Location.Z / 16 != 0)
FlushMeshFlags |= 1 << (Location.Z / 16 - 1);
if (Location.Z % 16 == 15 && Location.Z / 16 != 15)
FlushMeshFlags |= 1 << (Location.Z / 16 + 1);
const TMap<FIntPoint, AVoxelChunk*>& Chunks = VoxelWorld->GetChunks();
if (Location.X == 15)
{
FIntPoint NeighborLocation = FIntPoint(ChunkLocation.X + 1, ChunkLocation.Y);
if (Chunks.Contains(NeighborLocation))
{
AVoxelChunk* Neighbor = Chunks[NeighborLocation];
Neighbor->FlushMeshFlags |= 1 << (Location.Z / 16);
VoxelWorld->AddChunkToMeshFlushBuffer(NeighborLocation);
}
}
if (Location.X == 0)
{
FIntPoint NeighborLocation = FIntPoint(ChunkLocation.X - 1, ChunkLocation.Y);
if (Chunks.Contains(NeighborLocation))
{
AVoxelChunk* Neighbor = Chunks[NeighborLocation];
Neighbor->FlushMeshFlags |= 1 << (Location.Z / 16);
VoxelWorld->AddChunkToMeshFlushBuffer(NeighborLocation);
}
}
if (Location.Y == 15)
{
FIntPoint NeighborLocation = FIntPoint(ChunkLocation.X, ChunkLocation.Y + 1);
if (Chunks.Contains(NeighborLocation))
{
AVoxelChunk* Neighbor = Chunks[NeighborLocation];
Neighbor->FlushMeshFlags |= 1 << (Location.Z / 16);
VoxelWorld->AddChunkToMeshFlushBuffer(NeighborLocation);
}
}
if (Location.Y == 0)
{
FIntPoint NeighborLocation = FIntPoint(ChunkLocation.X, ChunkLocation.Y - 1);
if (Chunks.Contains(NeighborLocation))
{
AVoxelChunk* Neighbor = Chunks[NeighborLocation];
Neighbor->FlushMeshFlags |= 1 << (Location.Z / 16);
VoxelWorld->AddChunkToMeshFlushBuffer(NeighborLocation);
}
}
VoxelWorld->AddChunkToMeshFlushBuffer(ChunkLocation);
}
void AVoxelChunk::FlushMeshs()
{
if (!FlushMeshFlags) return;
for (int32 i = 0; i < 16; ++i)
{
int32 FlushMeshFlag = 1 << i;
if (!(FlushMeshFlags & FlushMeshFlag))
continue;
FlushMeshSection(i);
}
FlushMeshFlags = 0;
}
void AVoxelChunk::FlushMaterials()
{
for (int32 i = 0; i < 16; ++i)
{
for (int32 j = 0; j < VoxelSubsystem->Materials.Num(); ++j)
{
MeshComponents[i]->SetMaterial(j, VoxelSubsystem->Materials[j]);
}
}
}
void AVoxelChunk::Load()
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_VoxelChunk_Load);
if (VoxelWorld->GetWorldSetting().ArchiveFolder.IsEmpty())
{
ArchiveFile.Empty();
return;
}
ArchiveFile = VoxelWorld->GetWorldSetting().ArchiveFolder / FString::Printf(TEXT("%08X%08X"), ChunkLocation.X, ChunkLocation.Y) + ChunkFileExtension;
if (FPaths::FileExists(ArchiveFile))
{
TArray<uint8> ChunkDataBuffer;
if (FFileHelper::LoadFileToArray(ChunkDataBuffer, *ArchiveFile))
{
FMemoryReader MemoryReader(ChunkDataBuffer);
UScriptStruct* VoxelBlockStruct = FVoxelBlock::StaticStruct();
for (int32 X = 0; X < 16; ++X)
{
for (int32 Y = 0; Y < 16; ++Y)
{
for (int32 Z = 0; Z < 256; ++Z)
{
VoxelBlockStruct->SerializeItem(MemoryReader, &Blocks[X][Y][Z], nullptr);
}
}
}
UE_LOG(LogVoxel, Log, TEXT("Load Chunk %d, %d From File '%s'"), ChunkLocation.X, ChunkLocation.Y, *ArchiveFile);
}
}
}
void AVoxelChunk::Unload()
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_VoxelChunk_Unload);
if (ArchiveFile.IsEmpty()) return;
TArray<uint8> ChunkDataBuffer;
FMemoryWriter MemoryWriter(ChunkDataBuffer);
UScriptStruct* VoxelBlockStruct = FVoxelBlock::StaticStruct();
for (int32 X = 0; X < 16; ++X)
{
for (int32 Y = 0; Y < 16; ++Y)
{
for (int32 Z = 0; Z < 256; ++Z)
{
VoxelBlockStruct->SerializeItem(MemoryWriter, &Blocks[X][Y][Z], nullptr);
}
}
}
if (FFileHelper::SaveArrayToFile(ChunkDataBuffer, *ArchiveFile))
{
UE_LOG(LogVoxel, Log, TEXT("Save Chunk %d, %d To File '%s'"), ChunkLocation.X, ChunkLocation.Y, *ArchiveFile);
}
else
{
UE_LOG(LogVoxel, Error, TEXT("Failed To Save Chunk %d, %d To File '%s'"), ChunkLocation.X, ChunkLocation.Y, *ArchiveFile);
}
}
void AVoxelChunk::FlushMeshSection(int32 SectionIndex)
{
static FVoxelMeshData CubeTopFaceBuffer = FVoxelMeshData::CubeTopFace;
static FVoxelMeshData CubeBottomFaceBuffer = FVoxelMeshData::CubeBottomFace;
static FVoxelMeshData CubeFrontFaceBuffer = FVoxelMeshData::CubeFrontFace;
static FVoxelMeshData CubeBackFaceBuffer = FVoxelMeshData::CubeBackFace;
static FVoxelMeshData CubeLeftFaceBuffer = FVoxelMeshData::CubeLeftFace;
static FVoxelMeshData CubeRightFaceBuffer = FVoxelMeshData::CubeRightFace;
MeshSectionBuffer.Reset();
FIntPoint FrontChunkLocation = FIntPoint(ChunkLocation.X + 1, ChunkLocation.Y);
FIntPoint BackChunkLocation = FIntPoint(ChunkLocation.X - 1, ChunkLocation.Y);
FIntPoint RightChunkLocation = FIntPoint(ChunkLocation.X, ChunkLocation.Y + 1);
FIntPoint LeftChunkLocation = FIntPoint(ChunkLocation.X, ChunkLocation.Y - 1);
const TMap<FIntPoint, AVoxelChunk*>& Chunks = VoxelWorld->GetChunks();
AVoxelChunk* FrontChunk = Chunks.Contains(FrontChunkLocation) ? Chunks[FrontChunkLocation] : nullptr;
AVoxelChunk* BackChunk = Chunks.Contains(BackChunkLocation) ? Chunks[BackChunkLocation] : nullptr;
AVoxelChunk* RightChunk = Chunks.Contains(RightChunkLocation) ? Chunks[RightChunkLocation] : nullptr;
AVoxelChunk* LeftChunk = Chunks.Contains(LeftChunkLocation) ? Chunks[LeftChunkLocation] : nullptr;
for (int32 X = 0; X < 16; ++X)
{
for (int32 Y = 0; Y < 16; ++Y)
{
for (int32 Z = 0 + SectionIndex * 16; Z < 16 + SectionIndex * 16; ++Z)
{
const FVoxelBlockType& CurrentVoxelBlock = VoxelSubsystem->GetBlockType(Blocks[X][Y][Z].Type);
if (CurrentVoxelBlock.Shape != EVoxelBlockShape::Cube) continue;
const FVoxelBlockType& TopVoxelBlock = VoxelSubsystem->GetBlockType(Z + 1 < 256 ? Blocks[X][Y][Z + 1].Type : TEXT("Air"));
const FVoxelBlockType& BottomVoxelBlock = VoxelSubsystem->GetBlockType(Z - 1 >= 0 ? Blocks[X][Y][Z - 1].Type : TEXT("Air"));
const FVoxelBlockType& FrontVoxelBlock = VoxelSubsystem->GetBlockType(X + 1 < 16 ? Blocks[X + 1][Y][Z].Type : (FrontChunk ? FrontChunk->GetBlockByRelativeLocation(FIntVector(0, Y, Z)).Type : TEXT("Air")));
const FVoxelBlockType& BackVoxelBlock = VoxelSubsystem->GetBlockType(X - 1 >= 0 ? Blocks[X - 1][Y][Z].Type : (BackChunk ? BackChunk->GetBlockByRelativeLocation(FIntVector(15, Y, Z)).Type : TEXT("Air")));
const FVoxelBlockType& LeftVoxelBlock = VoxelSubsystem->GetBlockType(Y - 1 >= 0 ? Blocks[X][Y - 1][Z].Type : (LeftChunk ? LeftChunk->GetBlockByRelativeLocation(FIntVector(X, 15, Z)).Type : TEXT("Air")));
const FVoxelBlockType& RightVoxelBlock = VoxelSubsystem->GetBlockType(Y + 1 < 16 ? Blocks[X][Y + 1][Z].Type : (RightChunk ? RightChunk->GetBlockByRelativeLocation(FIntVector(X, 0, Z)).Type : TEXT("Air")));
if (TopVoxelBlock.Shape != EVoxelBlockShape::Cube)
{
for (FVector2D& UV3 : CubeTopFaceBuffer.UV3)
UV3 = CurrentVoxelBlock.CustomTopFaceUV;
MeshSectionBuffer.Append(CubeTopFaceBuffer, FVector(X, Y, Z) * 100.0f);
}
if (BottomVoxelBlock.Shape != EVoxelBlockShape::Cube)
{
for (FVector2D& UV3 : CubeBottomFaceBuffer.UV3)
UV3 = CurrentVoxelBlock.CustomBottomFaceUV;
MeshSectionBuffer.Append(CubeBottomFaceBuffer, FVector(X, Y, Z) * 100.0f);
}
if (FrontVoxelBlock.Shape != EVoxelBlockShape::Cube)
{
for (FVector2D& UV3 : CubeFrontFaceBuffer.UV3)
UV3 = CurrentVoxelBlock.CustomFrontFaceUV;
MeshSectionBuffer.Append(CubeFrontFaceBuffer, FVector(X, Y, Z) * 100.0f);
}
if (BackVoxelBlock.Shape != EVoxelBlockShape::Cube)
{
for (FVector2D& UV3 : CubeBackFaceBuffer.UV3)
UV3 = CurrentVoxelBlock.CustomBackFaceUV;
MeshSectionBuffer.Append(CubeBackFaceBuffer, FVector(X, Y, Z) * 100.0f);
}
if (LeftVoxelBlock.Shape != EVoxelBlockShape::Cube)
{
for (FVector2D& UV3 : CubeLeftFaceBuffer.UV3)
UV3 = CurrentVoxelBlock.CustomLeftFaceUV;
MeshSectionBuffer.Append(CubeLeftFaceBuffer, FVector(X, Y, Z) * 100.0f);
}
if (RightVoxelBlock.Shape != EVoxelBlockShape::Cube)
{
for (FVector2D& UV3 : CubeRightFaceBuffer.UV3)
UV3 = CurrentVoxelBlock.CustomRightFaceUV;
MeshSectionBuffer.Append(CubeRightFaceBuffer, FVector(X, Y, Z) * 100.0f);
}
}
}
}
MeshComponents[SectionIndex]->CreateMeshSection_LinearColor
(
0,
MeshSectionBuffer.Vertices,
MeshSectionBuffer.Triangles,
MeshSectionBuffer.Normals,
MeshSectionBuffer.UV0,
MeshSectionBuffer.UV1,
MeshSectionBuffer.UV2,
MeshSectionBuffer.UV3,
MeshSectionBuffer.VertexColors,
TArray<FProcMeshTangent>(),
true
);
}

View File

@ -0,0 +1,38 @@
#include "VoxelHelper.h"
#include "VoxelWorld.h"
AVoxelWorld * UVoxelHelper::CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting)
{
UWorld* World = WorldContextObject->GetWorld();
if (!World) return nullptr;
AVoxelWorld* VoxelWorld = World->SpawnActor<AVoxelWorld>();
VoxelWorld->WorldSetting = WorldSetting;
return VoxelWorld;
}
void UVoxelHelper::WorldToRelativeLocation(const FIntVector & InWorldLocation, FIntPoint & OutChunkLocation, FIntVector & OutRelativeLocation)
{
OutChunkLocation.X = InWorldLocation.X / 16;
OutChunkLocation.Y = InWorldLocation.Y / 16;
OutRelativeLocation.X = InWorldLocation.X % 16;
OutRelativeLocation.Y = InWorldLocation.Y % 16;
OutRelativeLocation.Z = InWorldLocation.Z;
if (OutRelativeLocation.X < 0)
{
OutRelativeLocation.X += 16;
OutChunkLocation.X -= 1;
}
if (OutRelativeLocation.Y < 0)
{
OutRelativeLocation.Y += 16;
OutChunkLocation.Y -= 1;
}
}

View File

@ -0,0 +1,3 @@
#include "VoxelLog.h"
DEFINE_LOG_CATEGORY(LogVoxel);

View File

@ -0,0 +1,426 @@
#include "VoxelMesh.h"
const FVoxelMeshData FVoxelMeshData::CubeTopFace =
{
// Vertices
{
{ 0.0f, 0.0f, 100.0f },
{ 100.0f, 0.0f, 100.0f },
{ 0.0f, 100.0f, 100.0f },
{ 100.0f, 100.0f, 100.0f },
},
// Triangles
{
2, 1, 0,
2, 3, 1,
},
// Normals
{
{ 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, 1.0f },
},
// UV0
{
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 0.0f, 1.0f },
{ 1.0f, 1.0f },
},
// UV1
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV2
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV3
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// VertexColors
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
},
};
const FVoxelMeshData FVoxelMeshData::CubeBottomFace =
{
// Vertices
{
{ 0.0f, 0.0f, 0.0f },
{ 100.0f, 0.0f, 0.0f },
{ 0.0f, 100.0f, 0.0f },
{ 100.0f, 100.0f, 0.0f },
},
// Triangles
{
0, 1, 2,
1, 3, 2,
},
// Normals
{
{ 0.0f, 0.0f, -1.0f },
{ 0.0f, 0.0f, -1.0f },
{ 0.0f, 0.0f, -1.0f },
{ 0.0f, 0.0f, -1.0f },
},
// UV0
{
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 0.0f, 1.0f },
{ 1.0f, 1.0f },
},
// UV1
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV2
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV3
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// VertexColors
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
},
};
const FVoxelMeshData FVoxelMeshData::CubeFrontFace =
{
// Vertices
{
{ 100.0f, 0.0f, 0.0f },
{ 100.0f, 0.0f, 100.0f },
{ 100.0f, 100.0f, 0.0f },
{ 100.0f, 100.0f, 100.0f },
},
// Triangles
{
0, 1, 2,
1, 3, 2,
},
// Normals
{
{ 1.0f, 0.0f, 0.0f },
{ 1.0f, 0.0f, 0.0f },
{ 1.0f, 0.0f, 0.0f },
{ 1.0f, 0.0f, 0.0f },
},
// UV0
{
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
},
// UV1
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV2
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV3
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// VertexColors
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
},
};
const FVoxelMeshData FVoxelMeshData::CubeBackFace =
{
// Vertices
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 100.0f },
{ 0.0f, 100.0f, 0.0f },
{ 0.0f, 100.0f, 100.0f },
},
// Triangles
{
2, 1, 0,
2, 3, 1,
},
// Normals
{
{ -1.0f, 0.0f, 0.0f },
{ -1.0f, 0.0f, 0.0f },
{ -1.0f, 0.0f, 0.0f },
{ -1.0f, 0.0f, 0.0f },
},
// UV0
{
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
},
// UV1
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV2
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV3
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// VertexColors
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
},
};
const FVoxelMeshData FVoxelMeshData::CubeLeftFace =
{
// Vertices
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 100.0f },
{ 100.0f, 0.0f, 0.0f },
{ 100.0f, 0.0f, 100.0f },
},
// Triangles
{
0, 1, 2,
1, 3, 2,
},
// Normals
{
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
},
// UV0
{
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
},
// UV1
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV2
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV3
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// VertexColors
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
},
};
const FVoxelMeshData FVoxelMeshData::CubeRightFace =
{
// Vertices
{
{ 0.0f, 100.0f, 0.0f },
{ 0.0f, 100.0f, 100.0f },
{ 100.0f, 100.0f, 0.0f },
{ 100.0f, 100.0f, 100.0f },
},
// Triangles
{
2, 1, 0,
2, 3, 1,
},
// Normals
{
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
},
// UV0
{
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
},
// UV1
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV2
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// UV3
{
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
},
// VertexColors
{
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f },
},
};
void FVoxelMeshData::Reset()
{
Vertices.Reset();
Triangles.Reset();
Normals.Reset();
UV0.Reset();
UV1.Reset();
UV2.Reset();
UV3.Reset();
VertexColors.Reset();
}
void FVoxelMeshData::Append(const FVoxelMeshData & Source)
{
Vertices.Append(Source.Vertices);
Triangles.Append(Source.Triangles);
Normals.Append(Source.Normals);
UV0.Append(Source.UV0);
UV1.Append(Source.UV1);
UV2.Append(Source.UV2);
UV3.Append(Source.UV3);
VertexColors.Append(Source.VertexColors);
for (int32 i = -Source.Triangles.Num(); i < 0; ++i)
Triangles[Triangles.Num() + i] += Vertices.Num() - Source.Vertices.Num();
}
void FVoxelMeshData::Append(const FVoxelMeshData & Source, const FVector & LocationOffset)
{
Append(Source);
for (int32 i = -Source.Vertices.Num(); i < 0; ++i)
Vertices[Vertices.Num() + i] += LocationOffset;
}

View File

@ -0,0 +1,16 @@
#include "VoxelSubsystem.h"
#include "VoxelBlock.h"
UVoxelSubsystem::UVoxelSubsystem(const class FObjectInitializer& ObjectInitializer)
{
BlockTypes.Add(TEXT("Air"), FVoxelBlockType());
}
const FVoxelBlockType & UVoxelSubsystem::GetBlockType(const FName & Name) const
{
if (BlockTypes.Contains(Name))
return BlockTypes[Name];
return FVoxelBlockType::InvalidBlockType;
}

View File

@ -0,0 +1,317 @@
#include "VoxelWorld.h"
#include "VoxelLog.h"
#include "VoxelBlock.h"
#include "VoxelChunk.h"
#include "VoxelHelper.h"
#include "VoxelSubsystem.h"
#include "VoxelAgentInterface.h"
const TArray<FIntPoint> ChunkLoadOrder =
{
{ 0, 0 },
{ 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { -1, -1 }, { 1, -1 }, { -1, 1 }, { 1, 1 },
{ 2, 0 }, { -2, 0 }, { 0, -2 }, { 0, 2 }, { -2, 1 }, { 1, 2 }, { 1, -2 }, { -1, -2 },
{ 2, 1 }, { 2, -1 }, { -1, 2 }, { -2, -1 }, { -2, -2 }, { 2, 2 }, { 2, -2 }, { -2, 2 },
{ 0, -3 }, { 3, 0 }, { -3, 0 }, { 0, 3 }, { 3, -1 }, { -3, 1 }, { 1, -3 }, { -1, -3 },
{ -1, 3 }, { 1, 3 }, { 3, 1 }, { -3, -1 }, { 3, -2 }, { 2, -3 }, { -3, 2 }, { -3, -2 },
{ 3, 2 }, { -2, -3 }, { -2, 3 }, { 2, 3 }, { 4, 0 }, { 0, 4 }, { -4, 0 }, { 0, -4 },
{ 4, 1 }, { -1, 4 }, { -4, 1 }, { 4, -1 }, { 1, -4 }, { 1, 4 }, { -4, -1 }, { -1, -4 },
{ 3, -3 }, { -3, 3 }, { -3, -3 }, { 3, 3 }, { 4, -2 }, { -2, 4 }, { -2, -4 }, { -4, -2 },
{ -4, 2 }, { 2, 4 }, { 2, -4 }, { 4, 2 }, { 3, -4 }, { -5, 0 }, { 0, 5 }, { -3, 4 },
{ 4, -3 }, { -4, 3 }, { 5, 0 }, { 4, 3 }, { -4, -3 }, { 0, -5 }, { 3, 4 }, { -3, -4 },
{ -5, -1 }, { -5, 1 }, { 5, -1 }, { 5, 1 }, { -1, 5 }, { -1, -5 }, { 1, -5 }, { 1, 5 },
{ 5, -2 }, { 5, 2 }, { 2, -5 }, { -2, -5 }, { -5, 2 }, { -5, -2 }, { 2, 5 }, { -2, 5 },
{ -4, 4 }, { 4, 4 }, { -4, -4 }, { 4, -4 }, { -5, -3 }, { -3, 5 }, { 5, 3 }, { 3, 5 },
{ -5, 3 }, { 3, -5 }, { 5, -3 }, { -3, -5 }, { -6, 0 }, { 0, 6 }, { 6, 0 }, { 0, -6 },
{ 6, -1 }, { -6, -1 }, { -6, 1 }, { -1, 6 }, { -1, -6 }, { 1, -6 }, { 1, 6 }, { 6, 1 },
{ 2, -6 }, { -6, -2 }, { 6, 2 }, { 2, 6 }, { -6, 2 }, { -2, 6 }, { -2, -6 }, { 6, -2 },
{ 4, -5 }, { 5, -4 }, { -5, 4 }, { 5, 4 }, { -5, -4 }, { -4, -5 }, { 4, 5 }, { -4, 5 },
{ -6, -3 }, { 3, -6 }, { -3, -6 }, { -6, 3 }, { 6, 3 }, { 3, 6 }, { 6, -3 }, { -3, 6 },
{ 0, 7 }, { 0, -7 }, { 7, 0 }, { -7, 0 }, { 5, -5 }, { 1, 7 }, { -7, -1 }, { -7, 1 },
{ 1, -7 }, { -1, -7 }, { -5, -5 }, { 7, 1 }, { 5, 5 }, { -1, 7 }, { 7, -1 }, { -5, 5 },
{ 6, -4 }, { -4, -6 }, { -6, 4 }, { -6, -4 }, { 6, 4 }, { 4, 6 }, { 4, -6 }, { -4, 6 },
{ -2, 7 }, { 7, 2 }, { -2, -7 }, { -7, -2 }, { 2, -7 }, { 2, 7 }, { 7, -2 }, { -7, 2 },
{ -7, 3 }, { 7, 3 }, { -7, -3 }, { -3, -7 }, { -3, 7 }, { 7, -3 }, { 3, 7 }, { 3, -7 },
{ 6, -5 }, { -5, 6 }, { 6, 5 }, { -6, -5 }, { -5, -6 }, { 5, -6 }, { 5, 6 }, { -6, 5 },
{ 0, -8 }, { 0, 8 }, { -8, 0 }, { 8, 0 }, { 7, 4 }, { -4, -7 }, { 7, -4 }, { 1, 8 },
{ -1, -8 }, { 1, -8 }, { 4, -7 }, { 4, 7 }, { -7, -4 }, { -7, 4 }, { -8, 1 }, { -8, -1 },
{ -1, 8 }, { 8, 1 }, { 8, -1 }, { -4, 7 }, { 2, -8 }, { -2, 8 }, { -2, -8 }, { -8, -2 },
{ 8, 2 }, { 2, 8 }, { -8, 2 }, { 8, -2 }, { -6, 6 }, { -6, -6 }, { 6, 6 }, { 6, -6 },
{ 8, -3 }, { 3, 8 }, { -3, 8 }, { 8, 3 }, { 3, -8 }, { -8, -3 }, { -8, 3 }, { -3, -8 },
{ -5, -7 }, { 5, 7 }, { 7, -5 }, { -7, -5 }, { 7, 5 }, { -7, 5 }, { -5, 7 }, { 5, -7 },
{ 4, 8 }, { -4, 8 }, { -8, 4 }, { -8, -4 }, { 4, -8 }, { 8, -4 }, { 8, 4 }, { -4, -8 },
{ 0, -9 }, { 0, 9 }, { -9, 0 }, { 9, 0 }, { -1, -9 }, { 1, 9 }, { 9, -1 }, { -1, 9 },
{ 1, -9 }, { -9, 1 }, { -9, -1 }, { 9, 1 }, { 6, 7 }, { -7, 6 }, { -9, -2 }, { 2, 9 },
{ -2, -9 }, { -2, 9 }, { 9, 2 }, { -6, -7 }, { 7, -6 }, { -6, 7 }, { 7, 6 }, { 6, -7 },
{ 2, -9 }, { 9, -2 }, { -9, 2 }, { -7, -6 }, { 8, -5 }, { -5, 8 }, { -8, -5 }, { 5, 8 },
{ -5, -8 }, { 8, 5 }, { 5, -8 }, { -8, 5 }, { -3, 9 }, { -9, 3 }, { -9, -3 }, { 9, -3 },
{ 3, 9 }, { -3, -9 }, { 3, -9 }, { 9, 3 }, { -4, 9 }, { -9, -4 }, { -4, -9 }, { 4, 9 },
{ 9, 4 }, { 4, -9 }, { -9, 4 }, { 9, -4 }, { 7, 7 }, { -7, 7 }, { -7, -7 }, { 7, -7 },
{ -6, -8 }, { 10, 0 }, { 8, -6 }, { -8, -6 }, { 8, 6 }, { 6, -8 }, { -6, 8 }, { 0, -10 },
{ 0, 10 }, { -8, 6 }, { 6, 8 }, { -10, 0 }, { 10, -1 }, { -10, -1 }, { -1, -10 }, { -10, 1 },
{ -1, 10 }, { 10, 1 }, { 1, 10 }, { 1, -10 }, { 2, 10 }, { -10, 2 }, { -10, -2 }, { -2, 10 },
{ 2, -10 }, { 10, -2 }, { -2, -10 }, { 10, 2 }, { -9, -5 }, { -9, 5 }, { -5, -9 }, { 9, -5 },
{ 9, 5 }, { 5, 9 }, { 5, -9 }, { -5, 9 }, { 3, 10 }, { -10, 3 }, { 3, -10 }, { -3, 10 },
{ 10, -3 }, { -10, -3 }, { 10, 3 }, { -3, -10 }, { 8, -7 }, { 8, 7 }, { 7, 8 }, { -7, 8 },
{ -7, -8 }, { 7, -8 }, { -8, 7 }, { -8, -7 }, { 4, -10 }, { 10, 4 }, { -4, -10 }, { -10, -4 },
{ 10, -4 }, { -4, 10 }, { 4, 10 }, { -10, 4 }, { -6, -9 }, { 6, -9 }, { 6, 9 }, { -9, -6 },
{ -9, 6 }, { 9, -6 }, { 9, 6 }, { -6, 9 }, { 0, 11 }, { 11, 0 }, { 0, -11 }, { -11, 0 },
{ 1, 11 }, { -1, -11 }, { -1, 11 }, { -11, -1 }, { 11, 1 }, { 11, -1 }, { 1, -11 }, { -11, 1 },
{ -5, -10 }, { -2, -11 }, { 11, 2 }, { -10, -5 }, { 2, 11 }, { 10, -5 }, { 5, -10 }, { 11, -2 },
{ -5, 10 }, { -11, 2 }, { 10, 5 }, { 5, 10 }, { 2, -11 }, { -11, -2 }, { -10, 5 }, { -2, 11 },
{ -8, -8 }, { -8, 8 }, { 8, 8 }, { 8, -8 }, { 7, 9 }, { -11, 3 }, { -11, -3 }, { 11, -3 },
{ 9, 7 }, { -3, -11 }, { 3, -11 }, { 7, -9 }, { -9, 7 }, { -7, -9 }, { -9, -7 }, { 11, 3 },
{ 9, -7 }, { -7, 9 }, { -3, 11 }, { 3, 11 }, { 10, -6 }, { 10, 6 }, { -10, -6 }, { -6, -10 },
{ -6, 10 }, { -10, 6 }, { 6, -10 }, { 6, 10 }, { -4, 11 }, { -11, 4 }, { -4, -11 }, { -11, -4 },
{ 11, -4 }, { 11, 4 }, { 4, -11 }, { 4, 11 }, { 12, 0 }, { 0, 12 }, { 0, -12 }, { -12, 0 },
{ 12, -1 }, { 8, -9 }, { -12, -1 }, { 1, 12 }, { -1, -12 }, { -12, 1 }, { 12, 1 }, { 9, -8 },
{ -1, 12 }, { 1, -12 }, { -9, 8 }, { -8, -9 }, { -9, -8 }, { -8, 9 }, { 9, 8 }, { 8, 9 },
{ -11, -5 }, { 5, -11 }, { 11, 5 }, { -5, 11 }, { -5, -11 }, { 5, 11 }, { -11, 5 }, { 11, -5 },
{ 12, -2 }, { 12, 2 }, { -2, 12 }, { -12, -2 }, { -12, 2 }, { -2, -12 }, { 2, -12 }, { 2, 12 },
{ 7, 10 }, { 7, -10 }, { -10, 7 }, { 10, -7 }, { -7, -10 }, { 10, 7 }, { -7, 10 }, { -10, -7 },
{ 12, -3 }, { 12, 3 }, { -3, 12 }, { 3, -12 }, { -12, 3 }, { -12, -3 }, { -3, -12 }, { 3, 12 },
{ -6, 11 }, { -11, -6 }, { -11, 6 }, { 6, 11 }, { 11, 6 }, { -6, -11 }, { 6, -11 }, { 11, -6 },
{ 12, -4 }, { 12, 4 }, { -12, 4 }, { 4, -12 }, { -4, -12 }, { -12, -4 }, { -4, 12 }, { 4, 12 },
{ 9, -9 }, { -9, -9 }, { 9, 9 }, { -9, 9 }, { -10, -8 }, { 8, -10 }, { -10, 8 }, { 10, -8 },
{ -8, 10 }, { 10, 8 }, { -8, -10 }, { 8, 10 }, { 12, -5 }, { 5, -12 }, { 0, -13 }, { 13, 0 },
{ -5, 12 }, { 5, 12 }, { -12, 5 }, { 0, 13 }, { -5, -12 }, { 12, 5 }, { -12, -5 }, { -13, 0 },
{ -11, -7 }, { 7, -11 }, { 11, -7 }, { -13, -1 }, { -13, 1 }, { 13, -1 }, { 13, 1 }, { 11, 7 },
{ -1, -13 }, { -7, 11 }, { -7, -11 }, { -1, 13 }, { 1, 13 }, { 1, -13 }, { 7, 11 }, { -11, 7 },
{ -2, 13 }, { 2, 13 }, { -13, 2 }, { 2, -13 }, { -2, -13 }, { 13, -2 }, { -13, -2 }, { 13, 2 },
{ -13, 3 }, { 3, 13 }, { 3, -13 }, { -13, -3 }, { -3, 13 }, { -3, -13 }, { 13, -3 }, { 13, 3 },
{ 6, -12 }, { -12, 6 }, { 12, -6 }, { -6, -12 }, { -12, -6 }, { -6, 12 }, { 6, 12 }, { 12, 6 },
{ 10, -9 }, { -10, 9 }, { -9, -10 }, { 9, -10 }, { 9, 10 }, { -9, 10 }, { -10, -9 }, { 10, 9 },
{ 8, 11 }, { 8, -11 }, { 11, -8 }, { 13, 4 }, { -8, 11 }, { -8, -11 }, { 4, 13 }, { -4, -13 },
{ -4, 13 }, { 11, 8 }, { 13, -4 }, { -11, -8 }, { -13, 4 }, { -11, 8 }, { 4, -13 }, { -13, -4 },
{ 12, -7 }, { 12, 7 }, { -12, -7 }, { 7, -12 }, { 7, 12 }, { -12, 7 }, { -7, 12 }, { -7, -12 },
{ 13, 5 }, { -5, 13 }, { -13, -5 }, { 5, -13 }, { -13, 5 }, { 5, 13 }, { 13, -5 }, { -5, -13 },
{ -14, 0 }, { 0, 14 }, { 0, -14 }, { 14, 0 }, { -14, 1 }, { 1, -14 }, { -14, -1 }, { -1, 14 },
{ -1, -14 }, { 1, 14 }, { 14, -1 }, { 14, 1 }, { -2, -14 }, { 2, -14 }, { 2, 14 }, { -10, -10 },
{ -14, 2 }, { 10, 10 }, { -14, -2 }, { 10, -10 }, { -2, 14 }, { -10, 10 }, { 14, -2 }, { 14, 2 },
{ 11, 9 }, { 11, -9 }, { -11, -9 }, { -11, 9 }, { 9, 11 }, { -9, 11 }, { -9, -11 }, { 9, -11 },
{ 6, -13 }, { -13, -6 }, { -14, 3 }, { -6, 13 }, { 6, 13 }, { 3, -14 }, { -3, 14 }, { -14, -3 },
{ 13, 6 }, { 14, -3 }, { 13, -6 }, { 3, 14 }, { -6, -13 }, { -13, 6 }, { -3, -14 }, { 14, 3 },
{ -8, -12 }, { 8, 12 }, { -8, 12 }, { -12, 8 }, { 12, -8 }, { -12, -8 }, { 8, -12 }, { 12, 8 },
{ 4, 14 }, { -14, 4 }, { 14, 4 }, { 14, -4 }, { -4, -14 }, { 4, -14 }, { -4, 14 }, { -14, -4 },
{ 7, 13 }, { -7, -13 }, { -13, 7 }, { -13, -7 }, { 13, -7 }, { -7, 13 }, { 7, -13 }, { 13, 7 },
{ -10, -11 }, { 5, -14 }, { -11, -10 }, { 5, 14 }, { -11, 10 }, { 14, -5 }, { -14, 5 }, { -14, -5 },
{ 10, -11 }, { 10, 11 }, { 11, -10 }, { 11, 10 }, { -5, 14 }, { -5, -14 }, { -10, 11 }, { 14, 5 },
{ 0, 15 }, { 9, 12 }, { -12, 9 }, { -9, 12 }, { 15, 0 }, { 12, -9 }, { 12, 9 }, { 0, -15 },
{ -15, 0 }, { -12, -9 }, { 9, -12 }, { -9, -12 }, { 1, 15 }, { 15, 1 }, { -15, -1 }, { -1, 15 },
{ -1, -15 }, { 15, -1 }, { -15, 1 }, { 1, -15 }, { -15, -2 }, { 2, -15 }, { 15, 2 }, { -2, -15 },
{ 2, 15 }, { 15, -2 }, { -2, 15 }, { -15, 2 }, { -6, 14 }, { 14, -6 }, { -14, 6 }, { -6, -14 },
{ 6, 14 }, { -14, -6 }, { 6, -14 }, { 14, 6 }, { 8, 13 }, { 13, 8 }, { -8, -13 }, { 13, -8 },
{ -13, -8 }, { -8, 13 }, { -13, 8 }, { 8, -13 }, { 3, 15 }, { 15, 3 }, { -3, -15 }, { -15, -3 },
{ -3, 15 }, { -15, 3 }, { 3, -15 }, { 15, -3 }, { 15, 4 }, { 4, -15 }, { -4, -15 }, { 4, 15 },
{ -4, 15 }, { 15, -4 }, { -15, 4 }, { -15, -4 }, { -11, -11 }, { 11, -11 }, { -11, 11 }, { 11, 11 },
{ 12, 10 }, { -12, 10 }, { -10, -12 }, { -10, 12 }, { 10, -12 }, { 10, 12 }, { -12, -10 }, { 12, -10 },
{ 7, -14 }, { 14, 7 }, { -14, 7 }, { 14, -7 }, { 7, 14 }, { -14, -7 }, { -7, -14 }, { -7, 14 },
{ -15, 5 }, { -13, -9 }, { -5, -15 }, { 13, -9 }, { -9, -13 }, { 9, -13 }, { 5, 15 }, { -9, 13 },
{ 9, 13 }, { 13, 9 }, { -5, 15 }, { -13, 9 }, { 5, -15 }, { 15, 5 }, { -15, -5 }, { 15, -5 },
{ 0, 16 }, { -16, 0 }, { 0, -16 }, { 16, 0 }, { -16, 1 }, { -16, -1 }, { 1, 16 }, { -1, 16 },
{ 1, -16 }, { -1, -16 }, { 16, -1 }, { 16, 1 }, { 2, -16 }, { -14, 8 }, { -2, 16 }, { 8, 14 },
{ 14, 8 }, { -2, -16 }, { -8, -14 }, { -8, 14 }, { -14, -8 }, { 16, 2 }, { 16, -2 }, { 2, 16 },
{ 14, -8 }, { -16, 2 }, { -16, -2 }, { 8, -14 }, { 6, 15 }, { 6, -15 }, { -6, -15 }, { 15, -6 },
{ -15, 6 }, { 15, 6 }, { -15, -6 }, { -6, 15 }, { -3, 16 }, { 3, 16 }, { 11, 12 }, { 12, -11 },
{ 12, 11 }, { -11, 12 }, { 16, -3 }, { 16, 3 }, { -16, 3 }, { -16, -3 }, { -3, -16 }, { -12, -11 },
{ 11, -12 }, { -11, -12 }, { -12, 11 }, { 3, -16 }, { -10, -13 }, { -10, 13 }, { -13, 10 }, { 13, -10 },
{ 10, -13 }, { 10, 13 }, { 13, 10 }, { -13, -10 }, { 16, -4 }, { -4, -16 }, { 16, 4 }, { 4, 16 },
{ 4, -16 }, { -4, 16 }, { -16, -4 }, { -16, 4 }, { 7, -15 }, { 15, -7 }, { -7, 15 }, { 15, 7 },
{ 7, 15 }, { -7, -15 }, { -15, 7 }, { -15, -7 }, { -14, 9 }, { -9, -14 }, { 9, -14 }, { -9, 14 },
{ 14, 9 }, { 14, -9 }, { 9, 14 }, { -14, -9 }, { -16, -5 }, { -5, -16 }, { 5, 16 }, { 16, -5 },
{ 5, -16 }, { -5, 16 }, { -16, 5 }, { 16, 5 }, { -12, 12 }, { 12, 12 }, { 12, -12 }, { -12, -12 },
{ -15, -8 }, { 8, 15 }, { 8, -15 }, { -8, 15 }, { -8, -15 }, { 15, -8 }, { 15, 8 }, { -15, 8 },
{ 13, -11 }, { 11, -13 }, { -11, 13 }, { -11, -13 }, { 11, 13 }, { 13, 11 }, { -13, 11 }, { -13, -11 },
{ 16, -6 }, { -6, 16 }, { 6, -16 }, { -16, 6 }, { 16, 6 }, { -16, -6 }, { 6, 16 }, { -6, -16 },
{ 14, 10 }, { -10, 14 }, { 14, -10 }, { -10, -14 }, { 10, -14 }, { -14, 10 }, { -14, -10 }, { 10, 14 },
{ -16, -7 }, { 16, -7 }, { -7, -16 }, { -7, 16 }, { 16, 7 }, { 7, 16 }, { -16, 7 }, { 7, -16 },
{ 9, -15 }, { 15, -9 }, { 9, 15 }, { 15, 9 }, { -15, 9 }, { -15, -9 }, { -9, -15 }, { -9, 15 },
{ 13, -12 }, { -12, 13 }, { -12, -13 }, { 13, 12 }, { 12, -13 }, { -13, -12 }, { 12, 13 }, { -13, 12 },
{ -14, 11 }, { 14, -11 }, { -14, -11 }, { -11, -14 }, { -11, 14 }, { 11, -14 }, { 14, 11 }, { 11, 14 },
{ -16, -8 }, { -16, 8 }, { -8, 16 }, { 8, -16 }, { 16, -8 }, { 8, 16 }, { -8, -16 }, { 16, 8 },
{ 15, 10 }, { -10, -15 }, { -15, 10 }, { -15, -10 }, { 10, 15 }, { 10, -15 }, { 15, -10 }, { -10, 15 },
{ 9, 16 }, { -9, -16 }, { 16, -9 }, { -16, -9 }, { -9, 16 }, { 9, -16 }, { -16, 9 }, { 16, 9 },
{ -13, -13 }, { -13, 13 }, { 13, 13 }, { 13, -13 }, { 12, 14 }, { -12, 14 }, { -12, -14 }, { 14, 12 },
{ 12, -14 }, { 14, -12 }, { -14, -12 }, { -14, 12 }, { 11, -15 }, { -11, -15 }, { -15, -11 }, { -11, 15 },
{ 15, 11 }, { 15, -11 }, { -15, 11 }, { 11, 15 }, { -10, 16 }, { -16, -10 }, { -10, -16 }, { 16, -10 },
{ 10, -16 }, { 10, 16 }, { 16, 10 }, { -16, 10 }, { 14, -13 }, { 13, 14 }, { 14, 13 }, { 13, -14 },
{ -13, -14 }, { -14, -13 }, { -13, 14 }, { -14, 13 }, { -15, -12 }, { 15, -12 }, { -12, -15 }, { -15, 12 },
{ -12, 15 }, { 12, -15 }, { 12, 15 }, { 15, 12 }, { -11, 16 }, { 16, -11 }, { 11, -16 }, { -11, -16 },
{ -16, 11 }, { -16, -11 }, { 11, 16 }, { 16, 11 }, { 14, 14 }, { -14, -14 }, { 14, -14 }, { -14, 14 },
{ 15, -13 }, { -13, -15 }, { -15, 13 }, { -13, 15 }, { 15, 13 }, { -15, -13 }, { 13, -15 }, { 13, 15 },
{ 16, -12 }, { 12, -16 }, { -12, -16 }, { 12, 16 }, { -12, 16 }, { -16, -12 }, { -16, 12 }, { 16, 12 },
{ -15, 14 }, { 14, -15 }, { -15, -14 }, { -14, 15 }, { 14, 15 }, { -14, -15 }, { 15, -14 }, { 15, 14 },
{ 16, -13 }, { 13, -16 }, { -16, 13 }, { 13, 16 }, { -16, -13 }, { -13, -16 }, { -13, 16 }, { 16, 13 },
{ -15, 15 }, { -15, -15 }, { 15, -15 }, { 15, 15 }, { 16, -14 }, { -16, 14 }, { 14, -16 }, { -16, -14 },
{ -14, -16 }, { -14, 16 }, { 14, 16 }, { 16, 14 }, { 16, -15 }, { -15, -16 }, { -16, 15 }, { -15, 16 },
{ -16, -15 }, { 15, -16 }, { 15, 16 }, { 16, 15 }, { -16, -16 }, { -16, 16 }, { 16, -16 }, { 16, 16 },
};
AVoxelWorld::AVoxelWorld(const class FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
}
void AVoxelWorld::BeginPlay()
{
Super::BeginPlay();
UGameInstance* GameInstance = GetGameInstance();
VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>();
}
void AVoxelWorld::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
ManageChunk();
FlushMeshs();
}
void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
TArray<FIntPoint> ChunksToUnload;
Chunks.GetKeys(ChunksToUnload);
for (const FIntPoint& Chunk : ChunksToUnload)
UnloadChunk(Chunk);
Super::EndPlay(EndPlayReason);
}
const FVoxelBlock & AVoxelWorld::GetBlockByWorldLocation(const FIntVector & Location) const
{
FIntPoint ChunkLocation;
FIntVector RelativeLocation;
UVoxelHelper::WorldToRelativeLocation(Location, ChunkLocation, RelativeLocation);
if (!Chunks.Contains(ChunkLocation))
{
UE_LOG(LogVoxel, Warning, TEXT("The Chunk %d, %d Is Not Loaded, Block %d, %d, %d Is Invalid"), ChunkLocation.X, ChunkLocation.Y, Location.X, Location.Y, Location.Z);
return FVoxelBlock::InvalidBlock;
}
return Chunks[ChunkLocation]->GetBlockByRelativeLocation(RelativeLocation);
}
void AVoxelWorld::SetBlockByWorldLocation(const FIntVector& Location, const FVoxelBlock& NewBlock)
{
FIntPoint ChunkLocation;
FIntVector RelativeLocation;
UVoxelHelper::WorldToRelativeLocation(Location, ChunkLocation, RelativeLocation);
if (!Chunks.Contains(ChunkLocation))
{
UE_LOG(LogVoxel, Warning, TEXT("The Chunk %d, %d Is Not Loaded, Block %d, %d, %d Is Invalid"), ChunkLocation.X, ChunkLocation.Y, Location.X, Location.Y, Location.Z);
return;
}
Chunks[ChunkLocation]->SetBlockByRelativeLocation(RelativeLocation, NewBlock);
}
void AVoxelWorld::LoadChunk(const FIntPoint & ChunkLocation)
{
if (Chunks.Contains(ChunkLocation)) return;
UWorld* World = GetWorld();
check(World);
AVoxelChunk* NewVoxelChunk = World->SpawnActor<AVoxelChunk>();
NewVoxelChunk->VoxelWorld = this;
NewVoxelChunk->ChunkLocation = ChunkLocation;
NewVoxelChunk->SetActorLocation(FVector(ChunkLocation.X * 1600.0f, ChunkLocation.Y * 1600.0f, 0.0f));
NewVoxelChunk->AttachToActor(this, FAttachmentTransformRules::KeepRelativeTransform);
NewVoxelChunk->FlushMaterials();
NewVoxelChunk->Load();
AddChunkToMeshFlushBuffer(ChunkLocation);
Chunks.Add(ChunkLocation, NewVoxelChunk);
UE_LOG(LogVoxel, Log, TEXT("The Chunk %d, %d Is Loaded"), ChunkLocation.X, ChunkLocation.Y);
}
void AVoxelWorld::UnloadChunk(const FIntPoint & ChunkLocation)
{
if (!Chunks.Contains(ChunkLocation)) return;
Chunks[ChunkLocation]->Unload();
Chunks[ChunkLocation]->Destroy();
Chunks.Remove(ChunkLocation);
UE_LOG(LogVoxel, Log, TEXT("The Chunk %d, %d Is Unload"), ChunkLocation.X, ChunkLocation.Y);
}
void AVoxelWorld::FlushMaterials()
{
for (const TPair<FIntPoint, AVoxelChunk*>& Chunk : Chunks)
{
Chunk.Value->FlushMaterials();
}
}
void AVoxelWorld::ManageChunk()
{
FIntPoint RootChunk;
FIntVector RLocation;
UVoxelHelper::WorldToRelativeLocation(IVoxelAgentInterface::Execute_GetAgentLocation(CenterAgent.GetObject()), RootChunk, RLocation);
// Load
for (const FIntPoint& Chunk : ChunkLoadOrder)
{
const FIntPoint WorldLocation = Chunk + RootChunk;
const FIntPoint RelativeLocation = Chunk;
const bool bChunkLoaded = Chunks.Contains(WorldLocation);
const bool bInLoadDistance = FMath::Abs(RelativeLocation.X) < VoxelSubsystem->ChunkLoadDistance && FMath::Abs(RelativeLocation.Y) < VoxelSubsystem->ChunkLoadDistance;
if (!bChunkLoaded && bInLoadDistance)
{
LoadChunk(WorldLocation);
break;
}
}
// Unload
int32 ChunkUnloadDistance = VoxelSubsystem->ChunkLoadDistance + VoxelSubsystem->ChunkUnloadBuffer;
for (const TPair<FIntPoint, AVoxelChunk*>& Chunk : Chunks)
{
const FIntPoint WorldLocation = Chunk.Key;
const FIntPoint RelativeLocation = WorldLocation - RootChunk;
const bool bInUnloadDistance = FMath::Abs(RelativeLocation.X) > ChunkUnloadDistance && FMath::Abs(RelativeLocation.Y) > ChunkUnloadDistance;
if (bInUnloadDistance)
{
UnloadChunk(WorldLocation);
break;
}
}
}
void AVoxelWorld::FlushMeshs()
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_VoxelWorld_FlushMeshs);
for (const FIntPoint& ChunkLocation : MeshFlushBuffer)
{
if (!Chunks.Contains(ChunkLocation))
continue;
AVoxelChunk* ChunkActor = Chunks[ChunkLocation];
if (!IsValid(ChunkActor))
continue;
ChunkActor->FlushMeshs();
}
MeshFlushBuffer.Reset();
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelBlock.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "VoxelBlueprintLibrary.generated.h"
struct FVoxelBlockType;
UCLASS()
class UVoxelBlueprintLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Voxel|Subsystem", meta = (WorldContext = "WorldContextObject"))
static void AddBlockType(const UObject* WorldContextObject, const FName& Name, const FVoxelBlockType& BlockType);
};

View File

@ -0,0 +1,15 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FVoxelModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};

View File

@ -0,0 +1,27 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "VoxelAgentInterface.generated.h"
UINTERFACE(MinimalAPI)
class UVoxelAgentInterface : public UInterface
{
GENERATED_BODY()
};
class VOXEL_API IVoxelAgentInterface
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Voxel|Agent")
FIntVector GetAgentLocation() const;
FIntVector GetAgentLocation_Implementation() const;
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Voxel|Agent")
FVector GetAgentPartialLocation() const;
FVector GetAgentPartialLocation_Implementation() const;
};

View File

@ -0,0 +1,66 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelMesh.h"
#include "UObject/Object.h"
#include "VoxelBlock.generated.h"
class AVoxelWorld;
USTRUCT(BlueprintType)
struct VOXEL_API FVoxelBlock
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FName Type;
FVoxelBlock() : FVoxelBlock(FName(TEXT("Air"))) { }
FVoxelBlock(FName InType) : Type(InType) { }
const static FVoxelBlock InvalidBlock;
bool IsValidBlock() const { return Type != NAME_None; }
};
UENUM(BlueprintType)
enum class EVoxelBlockShape : uint8
{
Invalid,
Air,
Cube,
};
USTRUCT(BlueprintType)
struct VOXEL_API FVoxelBlockType
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
EVoxelBlockShape Shape;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FVector2D CustomTopFaceUV;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FVector2D CustomBottomFaceUV;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FVector2D CustomFrontFaceUV;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FVector2D CustomBackFaceUV;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FVector2D CustomLeftFaceUV;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Block")
FVector2D CustomRightFaceUV;
FVoxelBlockType() : FVoxelBlockType(EVoxelBlockShape::Air) { }
FVoxelBlockType(EVoxelBlockShape InShape) : Shape(InShape) { }
const static FVoxelBlockType InvalidBlockType;
};

View File

@ -0,0 +1,74 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelBlock.h"
#include "GameFramework/Actor.h"
#include "VoxelChunk.generated.h"
class AVoxelWorld;
class UVoxelSubsystem;
class UProceduralMeshComponent;
const FString ChunkFileExtension = TEXT(".voxelchunk");
UCLASS(BlueprintType)
class VOXEL_API AVoxelChunk : public AActor
{
GENERATED_BODY()
friend AVoxelWorld;
public:
AVoxelChunk(const class FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk")
AVoxelWorld* GetVoxelWorld() const { return VoxelWorld; }
UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk")
FIntPoint GetChunkLocation() const { return ChunkLocation; }
UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk")
const FVoxelBlock& GetBlockByRelativeLocation(const FIntVector& Location) const;
UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk")
void SetBlockByRelativeLocation(const FIntVector& Location, const FVoxelBlock& NewBlock);
UFUNCTION(CallInEditor, BlueprintCallable, Category = "Voxel|Chunk")
void FlushMeshs();
UFUNCTION(CallInEditor, BlueprintCallable, Category = "Voxel|Chunk")
void FlushMaterials();
private:
UPROPERTY()
UVoxelSubsystem* VoxelSubsystem;
UPROPERTY()
AVoxelWorld* VoxelWorld;
UPROPERTY()
TArray<UProceduralMeshComponent*> MeshComponents;
FString ArchiveFile;
FIntPoint ChunkLocation;
uint16 FlushMeshFlags;
FVoxelBlock Blocks[16][16][256];
FVoxelMeshData MeshSectionBuffer;
private:
void Load();
void Unload();
void FlushMeshSection(int32 SectionIndex);
};

View File

@ -0,0 +1,23 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelWorld.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "VoxelHelper.generated.h"
class AVoxelWorld;
UCLASS()
class UVoxelHelper : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Voxel|Helper", meta = (WorldContext = "WorldContextObject"))
static AVoxelWorld* CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting);
UFUNCTION(BlueprintCallable, Category = "Voxel|Helper")
static void WorldToRelativeLocation(const FIntVector& InWorldLocation, FIntPoint& OutChunkLocation, FIntVector& OutRelativeLocation);
};

View File

@ -0,0 +1,5 @@
#pragma once
#include "Logging/LogMacros.h"
VOXEL_API DECLARE_LOG_CATEGORY_EXTERN(LogVoxel, Log, All);

View File

@ -0,0 +1,47 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelMesh.generated.h"
USTRUCT(BlueprintType)
struct FVoxelMeshData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FVector> Vertices;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<int32> Triangles;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FVector> Normals;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FVector2D> UV0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FVector2D> UV1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FVector2D> UV2;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FVector2D> UV3;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Mesh")
TArray<FLinearColor> VertexColors;
const static FVoxelMeshData CubeTopFace;
const static FVoxelMeshData CubeBottomFace;
const static FVoxelMeshData CubeFrontFace;
const static FVoxelMeshData CubeBackFace;
const static FVoxelMeshData CubeLeftFace;
const static FVoxelMeshData CubeRightFace;
void Reset();
void Append(const FVoxelMeshData& Source);
void Append(const FVoxelMeshData& Source, const FVector& LocationOffset);
};

View File

@ -0,0 +1,33 @@
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "VoxelSubsystem.generated.h"
struct FVoxelBlockType;
UCLASS()
class UVoxelSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
UVoxelSubsystem(const class FObjectInitializer& ObjectInitializer);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Subsystem")
int32 ChunkLoadDistance = 16;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Subsystem")
int32 ChunkUnloadBuffer = 2;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Subsystem")
TArray<UMaterial*> Materials;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Subsystem")
TMap<FName, FVoxelBlockType> BlockTypes;
UFUNCTION(BlueprintCallable, Category = "Voxel|Subsystem")
const FVoxelBlockType& GetBlockType(const FName& Name) const;
};

View File

@ -0,0 +1,88 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Info.h"
#include "VoxelWorld.generated.h"
struct FVoxelBlock;
class AVoxelChunk;
class UVoxelHelper;
class UVoxelBlockType;
class UVoxelSubsystem;
class IVoxelAgentInterface;
USTRUCT(BlueprintType)
struct FVoxelWorldSetting
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|World")
FString ArchiveFolder;
};
UCLASS(BlueprintType)
class VOXEL_API AVoxelWorld : public AInfo
{
GENERATED_BODY()
friend UVoxelHelper;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|World")
TScriptInterface<IVoxelAgentInterface> CenterAgent;
AVoxelWorld(const class FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UFUNCTION(BlueprintCallable, Category = "Voxel|World")
const FVoxelWorldSetting& GetWorldSetting() const { return WorldSetting; }
UFUNCTION(BlueprintCallable, Category = "Voxel|World")
const TMap<FIntPoint, AVoxelChunk*>& GetChunks() const { return Chunks; }
UFUNCTION(BlueprintCallable, Category = "Voxel|World")
const FVoxelBlock& GetBlockByWorldLocation(const FIntVector& Location) const;
UFUNCTION(BlueprintCallable, Category = "Voxel|World")
void SetBlockByWorldLocation(const FIntVector& Location, const FVoxelBlock& NewBlock);
UFUNCTION(BlueprintCallable, Category = "Voxel|World")
void AddChunkToMeshFlushBuffer(const FIntPoint& ChunkLocation) { MeshFlushBuffer.Add(ChunkLocation); }
UFUNCTION(CallInEditor, BlueprintCallable, Category = "Voxel|World")
void FlushMaterials();
public:
void LoadChunk(const FIntPoint& ChunkLocation);
void UnloadChunk(const FIntPoint& ChunkLocation);
private:
UPROPERTY(EditAnywhere, Category = "Voxel|World")
FVoxelWorldSetting WorldSetting;
UPROPERTY()
UVoxelSubsystem* VoxelSubsystem;
UPROPERTY()
TMap<FIntPoint, AVoxelChunk*> Chunks;
UPROPERTY()
TSet<FIntPoint> MeshFlushBuffer;
private:
void ManageChunk();
void FlushMeshs();
};

View File

@ -0,0 +1,54 @@
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class Voxel : ModuleRules
{
public Voxel(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"ProceduralMeshComponent",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}

30
Voxel.uplugin Normal file
View File

@ -0,0 +1,30 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "Voxel",
"Description": "",
"Category": "Other",
"CreatedBy": "_Redstone_c_",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
{
"Name": "Voxel",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "ProceduralMeshComponent",
"Enabled": true
}
]
}