Decoupled Chunk data loading/generation and geometry generation

This commit is contained in:
Simon Lübeß
2021-03-19 18:06:40 +01:00
parent a0373366f6
commit 72400e873d
5 changed files with 222 additions and 22 deletions
+3 -2
View File
@@ -1,5 +1,6 @@
using GlitchyEngine.Math;
using GlitchyEngine; using GlitchyEngine;
using GlitchyEngine.Math;
namespace Sandbox.VoxelFun namespace Sandbox.VoxelFun
{ {
class Block class Block
@@ -34,7 +35,7 @@ namespace Sandbox.VoxelFun
*/ */
public virtual void OnPlacing(Int32_3 blockCoordinate) public virtual void OnPlacing(Int32_3 blockCoordinate)
{ {
Log.ClientLogger.Info($"I broke. {{{blockCoordinate}}}"); Log.ClientLogger.Info($"I live! {{{blockCoordinate}}}");
} }
} }
} }
+61 -7
View File
@@ -26,6 +26,9 @@ namespace Sandbox.VoxelFun
private bool _isDirty; private bool _isDirty;
private bool _isGeometryDirty; private bool _isGeometryDirty;
/// Neighbors that will trigger a regeneration of this chunks geometry
public BlockFace _reqiredNeighbors;
public bool IsDirty => _isDirty; public bool IsDirty => _isDirty;
public bool IsGeometryDirty public bool IsGeometryDirty
@@ -196,7 +199,7 @@ namespace Sandbox.VoxelFun
SaveChunkToFile(chunk); SaveChunkToFile(chunk);
} }
GenChunkGeo(chunk); chunk.IsGeometryDirty = true;
using(chunkListLock.Enter()) using(chunkListLock.Enter())
{ {
@@ -212,10 +215,7 @@ namespace Sandbox.VoxelFun
} }
// Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk) // Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk)
using(_chunkLoadedLock.Enter()) OnChunkLoaded(chunkCoordinate);
{
_chunkLoaded.Invoke(chunkCoordinate);
}
} }
else if(!noBlocking) else if(!noBlocking)
{ {
@@ -256,6 +256,59 @@ namespace Sandbox.VoxelFun
return chunk; return chunk;
} }
void OnChunkLoaded(Int32_3 chunkCoordinate)
{
// Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk)
using(_chunkLoadedLock.Enter())
{
_chunkLoaded.Invoke(chunkCoordinate);
}
// Left
{
var chunkCoordinate;
chunkCoordinate.X--;
Chunk neighbor = GetChunk(chunkCoordinate);
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Right))
neighbor.IsGeometryDirty = true;
}
// Right
{
var chunkCoordinate;
chunkCoordinate.X++;
Chunk neighbor = GetChunk(chunkCoordinate);
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Left))
neighbor.IsGeometryDirty = true;
}
// Back
{
var chunkCoordinate;
chunkCoordinate.Z--;
Chunk neighbor = GetChunk(chunkCoordinate);
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Front))
neighbor.IsGeometryDirty = true;
}
// Front
{
var chunkCoordinate;
chunkCoordinate.Z++;
Chunk neighbor = GetChunk(chunkCoordinate);
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Back))
neighbor.IsGeometryDirty = true;
}
}
void SetChunkPos(Int32_3 chunkPos) void SetChunkPos(Int32_3 chunkPos)
{ {
chunkPosLock.Enter(); chunkPosLock.Enter();
@@ -543,7 +596,7 @@ namespace Sandbox.VoxelFun
{ {
var oldGeometry = chunk.Geometry; var oldGeometry = chunk.Geometry;
var newGeometry = voxelGeoGen.GenerateGeometry(chunk.Data); var newGeometry = voxelGeoGen.GenerateGeometry(chunk);
Interlocked.Store(ref chunk.Geometry, newGeometry); Interlocked.Store(ref chunk.Geometry, newGeometry);
chunk.IsGeometryDirty = false; chunk.IsGeometryDirty = false;
@@ -559,11 +612,12 @@ namespace Sandbox.VoxelFun
Chunk chunk = pair.value; Chunk chunk = pair.value;
GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry); GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry);
chunkGeo.AddRef();
if(chunkGeo == null) if(chunkGeo == null)
continue; continue;
chunkGeo.AddRef();
Texture.Bind(); Texture.Bind();
Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform); Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform);
+108 -7
View File
@@ -47,15 +47,69 @@ namespace Sandbox.VoxelFun
public GraphicsContext Context; public GraphicsContext Context;
public VertexLayout Layout; public VertexLayout Layout;
BlockFace GetVisibleFaces(VoxelChunk chunk, int x, int y, int z) BlockFace GetVisibleFaces(VoxelChunk chunk, int x, int y, int z, Chunk[3][3] chunks)
{ {
BlockFace visibleFaces = .None; BlockFace visibleFaces = .None;
if(z == 0 || chunk.Data[x][y][z - 1].VisibleNeighbors.HasFlag(.Front)) // Back
int idx = z;
Chunk readChunk = chunks[1][1];
if(idx == 0)
{
readChunk = chunks[1][0];
idx = VoxelChunk.Size.Z;
}
if(readChunk == null || readChunk.Data.Data[x][y][idx - 1].VisibleNeighbors.HasFlag(.Front))
visibleFaces |= .Back; visibleFaces |= .Back;
if(z == VoxelChunk.SizeZ - 1 || chunk.Data[x][y][z + 1].VisibleNeighbors.HasFlag(.Back))
// Front
idx = z + 1;
readChunk = chunks[1][1];
if(idx == VoxelChunk.Size.Z)
{
readChunk = chunks[1][2];
idx = 0;
}
if(readChunk == null || readChunk.Data.Data[x][y][idx].VisibleNeighbors.HasFlag(.Back))
visibleFaces |= .Front; visibleFaces |= .Front;
// Left
idx = x;
readChunk = chunks[1][1];
if(idx == 0)
{
readChunk = chunks[0][1];
idx = VoxelChunk.Size.X;
}
if(readChunk == null || readChunk.Data.Data[idx - 1][y][z].VisibleNeighbors.HasFlag(.Right))
visibleFaces |= .Left;
// Right
idx = x + 1;
readChunk = chunks[1][1];
if(idx == VoxelChunk.Size.X)
{
readChunk = chunks[2][1];
idx = 0;
}
if(readChunk == null || readChunk.Data.Data[idx][y][z].VisibleNeighbors.HasFlag(.Left))
visibleFaces |= .Right;
// TODO: implement for top and bottom as we have 3D chunks
if(y == 0 || chunk.Data[x][y - 1][z].VisibleNeighbors.HasFlag(.Top))
visibleFaces |= .Bottom;
if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom))
visibleFaces |= .Top;
/*
if(x == 0 || chunk.Data[x - 1][y][z].VisibleNeighbors.HasFlag(.Right)) if(x == 0 || chunk.Data[x - 1][y][z].VisibleNeighbors.HasFlag(.Right))
visibleFaces |= .Left; visibleFaces |= .Left;
if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z].VisibleNeighbors.HasFlag(.Left)) if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z].VisibleNeighbors.HasFlag(.Left))
@@ -65,11 +119,11 @@ namespace Sandbox.VoxelFun
visibleFaces |= .Bottom; visibleFaces |= .Bottom;
if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom)) if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom))
visibleFaces |= .Top; visibleFaces |= .Top;
*/
return visibleFaces; return visibleFaces;
} }
public GeometryBinding GenerateGeometry(VoxelChunk chunk) public GeometryBinding GenerateGeometry(Chunk chunk)
{ {
List<VertexColorTexture> vertices = scope List<VertexColorTexture>(); List<VertexColorTexture> vertices = scope List<VertexColorTexture>();
List<uint32> indices = scope List<uint32>(); List<uint32> indices = scope List<uint32>();
@@ -77,17 +131,64 @@ namespace Sandbox.VoxelFun
Stopwatch sw = .StartNew(); Stopwatch sw = .StartNew();
var chunkData = chunk.Data.Data;
Chunk[3][3] chunks;
var coord = chunk.Coordinate;
// left
coord.X -= 1;
chunks[0][1] = chunk.ChunkManager.GetChunk(coord);
if(chunks[0][1] == null)
{
// TODO: register reload when neighbor generated
chunk._reqiredNeighbors |= .Left;
}
// back
coord.X += 1;
coord.Z -= 1;
chunks[1][0] = chunk.ChunkManager.GetChunk(coord);
if(chunks[1][0] == null)
{
// TODO: register reload when neighbor generated
chunk._reqiredNeighbors |= .Back;
}
// center
chunks[1][1] = chunk;
// front
coord.Z += 2;
chunks[1][2] = chunk.ChunkManager.GetChunk(coord);
if(chunks[1][2] == null)
{
// TODO: register reload when neighbor generated
chunk._reqiredNeighbors |= .Front;
}
// right
coord.X += 1;
coord.Z -= 1;
chunks[2][1] = chunk.ChunkManager.GetChunk(coord);
if(chunks[2][1] == null)
{
// TODO: register reload when neighbor generated
chunk._reqiredNeighbors |= .Right;
}
for(int x < VoxelChunk.SizeX) for(int x < VoxelChunk.SizeX)
for(int y < VoxelChunk.SizeY) for(int y < VoxelChunk.SizeY)
for(int z < VoxelChunk.SizeZ) for(int z < VoxelChunk.SizeZ)
{ {
Block block = chunk.Data[x][y][z]; Block block = chunkData[x][y][z];
Vector3 blockPos = .(x, y, z); Vector3 blockPos = .(x, y, z);
if(block != Blocks.Air) if(block != Blocks.Air)
{ {
BlockFace visibleFaces = GetVisibleFaces(chunk, x, y, z); BlockFace visibleFaces = GetVisibleFaces(chunk.Data, x, y, z, chunks);
if(visibleFaces != .None) if(visibleFaces != .None)
block.Model.GenerateGeometry(block, blockPos, visibleFaces, vertices, indices, ref lastIndex); block.Model.GenerateGeometry(block, blockPos, visibleFaces, vertices, indices, ref lastIndex);
+4 -1
View File
@@ -408,6 +408,9 @@ namespace Sandbox.VoxelFun
if(intersectInfo.Face != .None) if(intersectInfo.Face != .None)
{ {
if(rightHandBlock == null)
rightHandBlock = Blocks.Stone;
if(Input.IsMouseButtonPressing(.LeftButton)) if(Input.IsMouseButtonPressing(.LeftButton))
{ {
_world.BreakBlock(intersectInfo.Coordinate); _world.BreakBlock(intersectInfo.Coordinate);
@@ -427,7 +430,7 @@ namespace Sandbox.VoxelFun
Renderer.EndScene(); Renderer.EndScene();
} }
Block rightHandBlock = Blocks.Stone; Block rightHandBlock;
struct IntersectionInfo struct IntersectionInfo
{ {
+41
View File
@@ -317,6 +317,8 @@ namespace Sandbox.VoxelFun
block.OnBreaking(blockCoordinate); block.OnBreaking(blockCoordinate);
chunk.SetBlock(coordInChunk, Blocks.Air); chunk.SetBlock(coordInChunk, Blocks.Air);
MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk);
} }
/** /**
@@ -336,6 +338,8 @@ namespace Sandbox.VoxelFun
block.OnPlacing(blockCoordinate); block.OnPlacing(blockCoordinate);
chunk.SetBlock(coordInChunk, block); chunk.SetBlock(coordInChunk, block);
MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk);
} }
/** /**
@@ -379,6 +383,43 @@ namespace Sandbox.VoxelFun
Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate); Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate);
chunk.SetBlock(coordInChunk, block); chunk.SetBlock(coordInChunk, block);
MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk);
}
void MarkNeighborGeometryDirty(Int32_3 chunkCoordinate, Int32_3 coordInChunk)
{
var chunkCoordinate;
Chunk chunk;
// if we are on a chunk border mark the neighbor as dirty
if(coordInChunk.X == 0)
{
chunkCoordinate.X--;
chunk = _chunkManager.GetChunk(chunkCoordinate);
chunk?.IsGeometryDirty = true;
}
else if(coordInChunk.X == VoxelChunk.Size.X - 1)
{
chunkCoordinate.X++;
chunk = _chunkManager.GetChunk(chunkCoordinate);
chunk?.IsGeometryDirty = true;
}
// TODO: implement Y
else if(coordInChunk.Z == 0)
{
chunkCoordinate.Z--;
chunk = _chunkManager.GetChunk(chunkCoordinate);
chunk?.IsGeometryDirty = true;
}
else if(coordInChunk.Z == VoxelChunk.Size.Z - 1)
{
chunkCoordinate.Z++;
chunk = _chunkManager.GetChunk(chunkCoordinate);
chunk?.IsGeometryDirty = true;
}
} }
/** /**