Improved island generation

This commit is contained in:
Harrison Corlett 2026-09-17 11:31:52 +01:00
parent 8c301d0ac1
commit 4565188f15
5 changed files with 91 additions and 126 deletions

View file

@ -29,6 +29,7 @@ import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.Noise2D;
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.PermutationArray;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Universal.Projection.Project3D;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelChunkGenerator;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
@ -658,14 +659,14 @@ public class GameCore implements GameLogic {
@Override
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
if(!PrimaryRuntime.IsServer && !RenderThread.Headless) {
CamPos.set(engineInstance.scene().GetCamera().GetPosition());
Camera cam = engineInstance.scene().GetCamera();
Project3D projection = engineInstance.scene().GetProjection();
CamPos.set(cam.GetPosition());
Vector3i ChunkPos = new Vector3i((int)Math.floor(CamPos.x/ (float) VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.y/ (float)VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.z/ (float)VoxelChunkGenerator.CHUNK_SIZE));
// if(ChunkPos.x != VoxelWorldManager.LastPosition.x || ChunkPos.y != VoxelWorldManager.LastPosition.y || ChunkPos.z != VoxelWorldManager.LastPosition.z) {
// VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(5, 5, 5));
// VoxelWorldManager.UnloadFarChunks(ChunkPos, 10);
//} else {
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,5,24));
VoxelWorldManager.UnloadFarChunks(ChunkPos, 24);
//}
for (int i = 0; i < VisualisedCollisionActor3D.CollisionVisuals.size(); i++) {
@ -685,6 +686,11 @@ public class GameCore implements GameLogic {
float PhysicsFramerate = 24f;
float PhysicsFrameTime = 1000f/PhysicsFramerate;
float DeltaTime = (float)FrameDiffNanoSeconds/(PhysicsFrameTime*1000000f);
Camera cam = engineInstance.scene().GetCamera();
Project3D projection = engineInstance.scene().GetProjection();
Vector3i ChunkPos = new Vector3i((int)Math.floor(CamPos.x/ (float) VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.y/ (float)VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.z/ (float)VoxelChunkGenerator.CHUNK_SIZE));
VoxelWorldManager.UnloadFarChunks(ChunkPos, 12,cam.GetViewMatrix(),projection.GetProjectionMatrix());
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(12,6,12),cam.GetViewMatrix(),projection.GetProjectionMatrix());
if(PrimaryRuntime.IsServer){
/* if(UseLegacyNetworking) Server.LegacyCollectIncomingPackets();
else*/ //Server.CollectIncomingPackets();

View file

@ -42,51 +42,35 @@ public class VoxelChunkGenerator {
pushConstants.putInt(24, indirectCommandIndex);
pushConstants.putInt(28, 0);
LongBuffer resetDescriptorSet = stack.longs(
allocator.GetDescriptorSet(resources.resetDescriptorId()).GetVkDescriptorSet()
);
LongBuffer voxelDescriptorSet = stack.longs(
allocator.GetDescriptorSet(resources.voxelGenerationDescriptorId()).GetVkDescriptorSet()
);
LongBuffer meshDescriptorSet = stack.longs(
allocator.GetDescriptorSet(resources.meshDescriptorId()).GetVkDescriptorSet()
);
LongBuffer resetDescriptorSet = stack.longs(allocator.GetDescriptorSet(
resources.resetDescriptorId()).GetVkDescriptorSet());
LongBuffer voxelDescriptorSet = stack.longs(allocator.GetDescriptorSet(
resources.voxelGenerationDescriptorId()).GetVkDescriptorSet());
LongBuffer meshDescriptorSet = stack.longs(allocator.GetDescriptorSet(
resources.meshDescriptorId()).GetVkDescriptorSet());
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipeline());
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipelineLayout(),0, resetDescriptorSet,null );
vkCmdPushConstants( cmd, resources.resetPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
vkCmdDispatch(cmd, 1, 1, 1);
VulkanUtils.BufferBarriers(stack, cmd,
new long[]{
VulkanUtils.BufferBarriers(stack, cmd, new long[]{
resources.meshPool().indirectPoolHandle(),
resources.counters().GetBuffer()
},
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
}, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.voxelGenerationPipeline().GetVulkanPipeline());
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.voxelGenerationPipeline().GetVulkanPipelineLayout(),0, voxelDescriptorSet,null );
vkCmdPushConstants( cmd, resources.voxelGenerationPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
VulkanUtils.BufferBarrier(stack, cmd,resources.voxelData().GetBuffer(),
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT
);
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT);
vkCmdBindPipeline(cmd,VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipeline() );
@ -96,22 +80,13 @@ public class VoxelChunkGenerator {
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
VulkanUtils.BufferBarriers(stack, cmd,
new long[]{
resources.voxelData().GetBuffer(),
resources.counters().GetBuffer(),
resources.meshPool().facePoolHandle(),
resources.meshPool().indirectPoolHandle()
},
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
VK_ACCESS_2_SHADER_READ_BIT |
VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT
);
VulkanUtils.BufferBarriers(stack, cmd, new long[]{
resources.voxelData().GetBuffer(), resources.counters().GetBuffer(),
resources.meshPool().facePoolHandle(), resources.meshPool().indirectPoolHandle()
}, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT, VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT);
}
}
}

View file

@ -5,8 +5,7 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.P
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.joml.Vector3i;
import org.joml.Vector4f;
import org.joml.*;
import org.lwjgl.vulkan.VkCommandBuffer;
import org.tinylog.Logger;
@ -17,8 +16,9 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import static org.lwjgl.vulkan.VK13.*;
public class VoxelWorldManager {
public static final int CHUNK_SIZE = 16;
private static final int MAX_RESIDENT_CHUNKS = 8192 * 2;
private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 256;
private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 128;
private static final ConcurrentLinkedQueue<Vector3i> RequestedChunks = new ConcurrentLinkedQueue<>();
private static final ConcurrentHashMap<Vector3i, RenderChunk> RenderChunks = new ConcurrentHashMap<>();
@ -63,7 +63,18 @@ public class VoxelWorldManager {
static Vector3i ChunkPos = new Vector3i(0, 0, 0);
static Vector3i ChunkPos2 = new Vector3i(0, 0, 0);
public static void GenerateChunks(Vector3i Position, Vector3i Radius) {
private static final FrustumIntersection frustumIntersection = new FrustumIntersection();
private static final Matrix4f viewProjectionMatrix = new Matrix4f();
private static Vector3f max = new Vector3f();
private static Vector3f max2 = new Vector3f();
private static Vector3f min = new Vector3f();
private static Vector3f min2 = new Vector3f();
public static void GenerateChunks(Vector3i Position, Vector3i Radius, Matrix4f cameraView,Matrix4f projectionMatrix) {
projectionMatrix.mul(cameraView, viewProjectionMatrix);
frustumIntersection.set(viewProjectionMatrix);
int ChunkX = Position.x;
int ChunkY = Position.y;
int ChunkY2 = Position.y;
@ -78,10 +89,18 @@ public class VoxelWorldManager {
ChunkY = Position.y + Ry;
ChunkY2 = Position.y - Ry;
ChunkZ = Position.z + Rz;
min.set(ChunkX * CHUNK_SIZE, ChunkY * CHUNK_SIZE, ChunkZ * CHUNK_SIZE);
min2.set(ChunkX * CHUNK_SIZE, ChunkY2 * CHUNK_SIZE, ChunkZ * CHUNK_SIZE);
max.set(min.x + CHUNK_SIZE, min.y + CHUNK_SIZE, min.z + CHUNK_SIZE);
max2.set(min2.x + CHUNK_SIZE, min2.y + CHUNK_SIZE, min2.z + CHUNK_SIZE);
if (Rx == -IterationX || Rz == -IterationX || Rx == IterationX || Rz == IterationX)
{
GenerateChunk(ChunkPos.set(ChunkX, ChunkY, ChunkZ));
GenerateChunk(ChunkPos2.set(ChunkX, ChunkY2, ChunkZ));
if(frustumIntersection.testAab(min.x, min.y, min.z, max.x, max.y, max.z)) {
GenerateChunk(ChunkPos.set(ChunkX, ChunkY, ChunkZ));
}
if(frustumIntersection.testAab(min2.x, min2.y, min2.z, max2.x, max2.y, max2.z)) {
GenerateChunk(ChunkPos2.set(ChunkX, ChunkY2, ChunkZ));
}
}
}
}
@ -171,19 +190,25 @@ public class VoxelWorldManager {
}
public static void UnloadFarChunks(Vector3i centerChunk, int unloadRadius) {
public static void UnloadFarChunks(Vector3i centerChunk, int unloadRadius,Matrix4f cameraView,Matrix4f projectionMatrix) {
int maxDistSq = unloadRadius * unloadRadius;
RenderChunks.entrySet().removeIf(entry -> {
Vector3i pos = entry.getKey();
projectionMatrix.mul(cameraView, viewProjectionMatrix);
frustumIntersection.set(viewProjectionMatrix);
min.set(pos.x * CHUNK_SIZE, pos.y * CHUNK_SIZE, pos.z * CHUNK_SIZE);
max.set(min.x + CHUNK_SIZE, min.y + CHUNK_SIZE, min.z + CHUNK_SIZE);
int dx = pos.x - centerChunk.x;
int dy = pos.y - centerChunk.y;
int dz = pos.z - centerChunk.z;
int distSq = dx * dx + dy * dy + dz * dz;
if (distSq > maxDistSq) {
boolean InView = frustumIntersection.testAab(min.x, min.y, min.z, max.x, max.y, max.z);
if (distSq > maxDistSq || !InView) {
RenderChunk chunk = entry.getValue();
Resources.meshPool().free(chunk);