实现基本 Cube 体素渲染
This commit is contained in:
commit
96e9af4438
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal 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
21
LICENSE
Normal 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
4
README.md
Normal 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
BIN
Resources/Icon128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
11
Source/Voxel/Private/Blueprint/VoxelBlueprintLibrary.cpp
Normal file
11
Source/Voxel/Private/Blueprint/VoxelBlueprintLibrary.cpp
Normal 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);
|
||||
}
|
20
Source/Voxel/Private/Voxel.cpp
Normal file
20
Source/Voxel/Private/Voxel.cpp
Normal 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)
|
11
Source/Voxel/Private/VoxelAgentInterface.cpp
Normal file
11
Source/Voxel/Private/VoxelAgentInterface.cpp
Normal 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);
|
||||
}
|
7
Source/Voxel/Private/VoxelBlock.cpp
Normal file
7
Source/Voxel/Private/VoxelBlock.cpp
Normal 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);
|
323
Source/Voxel/Private/VoxelChunk.cpp
Normal file
323
Source/Voxel/Private/VoxelChunk.cpp
Normal 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
|
||||
);
|
||||
}
|
38
Source/Voxel/Private/VoxelHelper.cpp
Normal file
38
Source/Voxel/Private/VoxelHelper.cpp
Normal 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;
|
||||
}
|
||||
}
|
3
Source/Voxel/Private/VoxelLog.cpp
Normal file
3
Source/Voxel/Private/VoxelLog.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "VoxelLog.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogVoxel);
|
426
Source/Voxel/Private/VoxelMesh.cpp
Normal file
426
Source/Voxel/Private/VoxelMesh.cpp
Normal 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;
|
||||
}
|
16
Source/Voxel/Private/VoxelSubsystem.cpp
Normal file
16
Source/Voxel/Private/VoxelSubsystem.cpp
Normal 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;
|
||||
}
|
317
Source/Voxel/Private/VoxelWorld.cpp
Normal file
317
Source/Voxel/Private/VoxelWorld.cpp
Normal 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();
|
||||
}
|
20
Source/Voxel/Public/Blueprint/VoxelBlueprintLibrary.h
Normal file
20
Source/Voxel/Public/Blueprint/VoxelBlueprintLibrary.h
Normal 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);
|
||||
|
||||
};
|
15
Source/Voxel/Public/Voxel.h
Normal file
15
Source/Voxel/Public/Voxel.h
Normal 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;
|
||||
};
|
27
Source/Voxel/Public/VoxelAgentInterface.h
Normal file
27
Source/Voxel/Public/VoxelAgentInterface.h
Normal 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;
|
||||
|
||||
};
|
66
Source/Voxel/Public/VoxelBlock.h
Normal file
66
Source/Voxel/Public/VoxelBlock.h
Normal 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;
|
||||
};
|
74
Source/Voxel/Public/VoxelChunk.h
Normal file
74
Source/Voxel/Public/VoxelChunk.h
Normal 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);
|
||||
|
||||
};
|
23
Source/Voxel/Public/VoxelHelper.h
Normal file
23
Source/Voxel/Public/VoxelHelper.h
Normal 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);
|
||||
|
||||
};
|
5
Source/Voxel/Public/VoxelLog.h
Normal file
5
Source/Voxel/Public/VoxelLog.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Logging/LogMacros.h"
|
||||
|
||||
VOXEL_API DECLARE_LOG_CATEGORY_EXTERN(LogVoxel, Log, All);
|
47
Source/Voxel/Public/VoxelMesh.h
Normal file
47
Source/Voxel/Public/VoxelMesh.h
Normal 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);
|
||||
};
|
33
Source/Voxel/Public/VoxelSubsystem.h
Normal file
33
Source/Voxel/Public/VoxelSubsystem.h
Normal 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;
|
||||
|
||||
};
|
88
Source/Voxel/Public/VoxelWorld.h
Normal file
88
Source/Voxel/Public/VoxelWorld.h
Normal 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();
|
||||
|
||||
};
|
54
Source/Voxel/Voxel.Build.cs
Normal file
54
Source/Voxel/Voxel.Build.cs
Normal 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
30
Voxel.uplugin
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user