From 72400e873dca00b7e454183c0971d8b495647f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Fri, 19 Mar 2021 18:06:40 +0100 Subject: [PATCH] Decoupled Chunk data loading/generation and geometry generation --- Sandbox/src/VoxelFun/Block.bf | 5 +- Sandbox/src/VoxelFun/ChunkManager.bf | 70 ++++++++-- .../src/VoxelFun/VoxelGeometryGenerator.bf | 123 ++++++++++++++++-- Sandbox/src/VoxelFun/VoxelTestLayer.bf | 5 +- Sandbox/src/VoxelFun/World.bf | 41 ++++++ 5 files changed, 222 insertions(+), 22 deletions(-) diff --git a/Sandbox/src/VoxelFun/Block.bf b/Sandbox/src/VoxelFun/Block.bf index 9318010..4f4247c 100644 --- a/Sandbox/src/VoxelFun/Block.bf +++ b/Sandbox/src/VoxelFun/Block.bf @@ -1,5 +1,6 @@ -using GlitchyEngine.Math; using GlitchyEngine; +using GlitchyEngine.Math; + namespace Sandbox.VoxelFun { class Block @@ -34,7 +35,7 @@ namespace Sandbox.VoxelFun */ public virtual void OnPlacing(Int32_3 blockCoordinate) { - Log.ClientLogger.Info($"I broke. {{{blockCoordinate}}}"); + Log.ClientLogger.Info($"I live! {{{blockCoordinate}}}"); } } } diff --git a/Sandbox/src/VoxelFun/ChunkManager.bf b/Sandbox/src/VoxelFun/ChunkManager.bf index e0a9747..f606e2b 100644 --- a/Sandbox/src/VoxelFun/ChunkManager.bf +++ b/Sandbox/src/VoxelFun/ChunkManager.bf @@ -26,6 +26,9 @@ namespace Sandbox.VoxelFun private bool _isDirty; private bool _isGeometryDirty; + /// Neighbors that will trigger a regeneration of this chunks geometry + public BlockFace _reqiredNeighbors; + public bool IsDirty => _isDirty; public bool IsGeometryDirty @@ -196,7 +199,7 @@ namespace Sandbox.VoxelFun SaveChunkToFile(chunk); } - GenChunkGeo(chunk); + chunk.IsGeometryDirty = true; 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) - using(_chunkLoadedLock.Enter()) - { - _chunkLoaded.Invoke(chunkCoordinate); - } + OnChunkLoaded(chunkCoordinate); } else if(!noBlocking) { @@ -256,6 +256,59 @@ namespace Sandbox.VoxelFun 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) { chunkPosLock.Enter(); @@ -543,7 +596,7 @@ namespace Sandbox.VoxelFun { var oldGeometry = chunk.Geometry; - var newGeometry = voxelGeoGen.GenerateGeometry(chunk.Data); + var newGeometry = voxelGeoGen.GenerateGeometry(chunk); Interlocked.Store(ref chunk.Geometry, newGeometry); chunk.IsGeometryDirty = false; @@ -559,11 +612,12 @@ namespace Sandbox.VoxelFun Chunk chunk = pair.value; GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry); - chunkGeo.AddRef(); - + if(chunkGeo == null) continue; + chunkGeo.AddRef(); + Texture.Bind(); Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform); diff --git a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf index adbccb1..a170c5b 100644 --- a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf +++ b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf @@ -47,15 +47,69 @@ namespace Sandbox.VoxelFun public GraphicsContext Context; 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; - - if(z == 0 || chunk.Data[x][y][z - 1].VisibleNeighbors.HasFlag(.Front)) - visibleFaces |= .Back; - if(z == VoxelChunk.SizeZ - 1 || chunk.Data[x][y][z + 1].VisibleNeighbors.HasFlag(.Back)) - visibleFaces |= .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; + + // 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; + + // 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)) visibleFaces |= .Left; if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z].VisibleNeighbors.HasFlag(.Left)) @@ -65,11 +119,11 @@ namespace Sandbox.VoxelFun visibleFaces |= .Bottom; if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom)) visibleFaces |= .Top; - + */ return visibleFaces; } - public GeometryBinding GenerateGeometry(VoxelChunk chunk) + public GeometryBinding GenerateGeometry(Chunk chunk) { List vertices = scope List(); List indices = scope List(); @@ -77,17 +131,64 @@ namespace Sandbox.VoxelFun Stopwatch sw = .StartNew(); - for(int x < VoxelChunk.SizeX) + 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 y < VoxelChunk.SizeY) for(int z < VoxelChunk.SizeZ) { - Block block = chunk.Data[x][y][z]; + Block block = chunkData[x][y][z]; Vector3 blockPos = .(x, y, z); if(block != Blocks.Air) { - BlockFace visibleFaces = GetVisibleFaces(chunk, x, y, z); + BlockFace visibleFaces = GetVisibleFaces(chunk.Data, x, y, z, chunks); if(visibleFaces != .None) block.Model.GenerateGeometry(block, blockPos, visibleFaces, vertices, indices, ref lastIndex); diff --git a/Sandbox/src/VoxelFun/VoxelTestLayer.bf b/Sandbox/src/VoxelFun/VoxelTestLayer.bf index 52fd25d..1d02c0d 100644 --- a/Sandbox/src/VoxelFun/VoxelTestLayer.bf +++ b/Sandbox/src/VoxelFun/VoxelTestLayer.bf @@ -408,6 +408,9 @@ namespace Sandbox.VoxelFun if(intersectInfo.Face != .None) { + if(rightHandBlock == null) + rightHandBlock = Blocks.Stone; + if(Input.IsMouseButtonPressing(.LeftButton)) { _world.BreakBlock(intersectInfo.Coordinate); @@ -427,7 +430,7 @@ namespace Sandbox.VoxelFun Renderer.EndScene(); } - Block rightHandBlock = Blocks.Stone; + Block rightHandBlock; struct IntersectionInfo { diff --git a/Sandbox/src/VoxelFun/World.bf b/Sandbox/src/VoxelFun/World.bf index e1d32e1..5981c0f 100644 --- a/Sandbox/src/VoxelFun/World.bf +++ b/Sandbox/src/VoxelFun/World.bf @@ -317,6 +317,8 @@ namespace Sandbox.VoxelFun block.OnBreaking(blockCoordinate); chunk.SetBlock(coordInChunk, Blocks.Air); + + MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk); } /** @@ -336,6 +338,8 @@ namespace Sandbox.VoxelFun block.OnPlacing(blockCoordinate); chunk.SetBlock(coordInChunk, block); + + MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk); } /** @@ -379,6 +383,43 @@ namespace Sandbox.VoxelFun Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate); 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; + } } /**