From bf9af81f38412dc058c2a171eacba37a172daf7e Mon Sep 17 00:00:00 2001 From: Halbear Date: Tue, 15 Sep 2026 20:49:24 +0100 Subject: [PATCH] what if minecraft ran on the GPU exclusively? glad you asked! because now it can --- .../VoxelComputeShaders/meshGeneration.glsl | 236 +++++++++++++ .../meshGenerationShared.glsl | 285 +++++++++++++++ .../VoxelComputeShaders/resetVoxelDraw.glsl | 27 ++ .../resetVoxelDrawShared.glsl | 42 +++ .../VoxelComputeShaders/voxelGeneration.glsl | 201 +++++++++++ .../voxelGenerationShared.glsl | 260 ++++++++++++++ .../shaders/forward_skybox_fragment.glsl.spv | Bin 780 -> 0 bytes .../shaders/lighting_frag.glsl | 2 - .../shaders/lighting_frag.glsl.spv | Bin 13336 -> 0 bytes .../multi-sampled_post_process_frag.glsl.spv | Bin 3704 -> 0 bytes .../shaders/post_process_frag.glsl.spv | Bin 6860 -> 0 bytes .../shaders/scene_fragment.glsl | 10 +- .../shaders/scene_fragment.glsl.spv | Bin 6344 -> 0 bytes .../shaders/scene_fragment_deferred.glsl | 11 +- .../shaders/scene_fragment_deferred.glsl.spv | Bin 11428 -> 0 bytes .../shaders/scene_opaque_fragment.glsl | 11 +- .../shaders/scene_opaque_fragment.glsl.spv | Bin 6344 -> 0 bytes .../scene_opaque_fragment_deferred.glsl | 10 +- .../shaders/scene_translucent_fragment.glsl | 10 +- .../scene_translucent_fragment.glsl.spv | Bin 6344 -> 0 bytes .../scene_translucent_fragment_deferred.glsl | 10 +- .../shaders/scene_vertex.glsl.spv | Bin 3264 -> 0 bytes .../shaders/skybox_fragment.glsl.spv | Bin 644 -> 0 bytes .../shaders/skybox_vertex.glsl.spv | Bin 2452 -> 0 bytes .../shaders/swap_frag.glsl.spv | Bin 872 -> 0 bytes .../EngineCore/Display/VulkanRenderer.java | 17 +- .../Terrain4J/EngineCore/Main/GameCore.java | 29 +- .../ComputeVoxelTerrain.java | 330 ++++++++++++++++++ .../VoxelTerrainGeneration/RenderChunk.java | 6 + .../SharedVoxelTerrainResources.java | 182 ++++++++++ .../VoxelChunkGenerator.java | 121 +++++++ .../VoxelChunkVisibility.java | 7 + .../VoxelTerrainGeneration/VoxelMeshPool.java | 126 +++++++ .../VoxelTerrainHeightSampler.java | 113 ++++++ .../VoxelWorldManager.java | 274 +++++++++++++++ .../Computing/VulkanUtil/ComputePipeline.java | 94 +++++ .../DeferredSceneRender.java | 3 + .../Forward/ForwardSceneRender.java | 2 + .../RenderPasses/Shadows/ShadowRenderer.java | 3 +- .../Rendering/Shader/DescriptorSet.java | 1 + .../RenderingAPI/Vulkan/Util/VulkanUtils.java | 44 +++ 41 files changed, 2433 insertions(+), 34 deletions(-) create mode 100644 resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl create mode 100644 resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl create mode 100644 resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl create mode 100644 resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl create mode 100644 resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl create mode 100644 resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl delete mode 100644 resources/EngineResources/shaders/forward_skybox_fragment.glsl.spv delete mode 100644 resources/EngineResources/shaders/lighting_frag.glsl.spv delete mode 100644 resources/EngineResources/shaders/multi-sampled_post_process_frag.glsl.spv delete mode 100644 resources/EngineResources/shaders/post_process_frag.glsl.spv delete mode 100644 resources/EngineResources/shaders/scene_fragment.glsl.spv delete mode 100644 resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv delete mode 100644 resources/EngineResources/shaders/scene_opaque_fragment.glsl.spv delete mode 100644 resources/EngineResources/shaders/scene_translucent_fragment.glsl.spv delete mode 100644 resources/EngineResources/shaders/scene_vertex.glsl.spv delete mode 100644 resources/EngineResources/shaders/skybox_fragment.glsl.spv delete mode 100644 resources/EngineResources/shaders/skybox_vertex.glsl.spv delete mode 100644 resources/EngineResources/shaders/swap_frag.glsl.spv create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/ComputeVoxelTerrain.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/RenderChunk.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkVisibility.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelMeshPool.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelTerrainHeightSampler.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VulkanUtil/ComputePipeline.java diff --git a/resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl b/resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl new file mode 100644 index 0000000..91b77ec --- /dev/null +++ b/resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl @@ -0,0 +1,236 @@ +#version 460 + +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +const int CHUNK_SIZE = 16; +const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; +const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; + +const uint FLOATS_PER_VERTEX = 14u; +const uint VERTICES_PER_FACE = 4u; +const uint INDICES_PER_FACE = 6u; + +const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * 12); +const uint MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * VERTICES_PER_FACE; +const uint MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * INDICES_PER_FACE; + +layout(std430, binding = 0) readonly buffer VoxelData { + uint voxels[]; +}; + +layout(std430, binding = 1) buffer VertexBuffer { + float vertices[]; +}; + +layout(std430, binding = 2) buffer IndexBuffer { + uint indices[]; +}; + +layout(std430, binding = 3) buffer DrawCommand { + uint indexCount; + uint instanceCount; + uint firstIndex; + int vertexOffset; + uint firstInstance; +} drawCmd; + +layout(std430, binding = 4) buffer Counters { + uint vertexCount; + uint indexCount; +} counters; + +layout(push_constant) uniform ChunkInfo { + ivec3 chunkPos; + int padding0; +}; + +uint flatten(ivec3 pos) { + return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z); +} + +uint getVoxel(ivec3 pos) { + if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0; + if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0; + if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0; + + return voxels[flatten(pos)]; +} + +void writeVertex(uint vertexIndex,vec3 position,vec3 normal, + vec3 tangent,vec3 bitangent,vec2 uv) { + uint base = vertexIndex * FLOATS_PER_VERTEX; + + vertices[base + 0u] = position.x; + vertices[base + 1u] = position.y; + vertices[base + 2u] = position.z; + + vertices[base + 3u] = normal.x; + vertices[base + 4u] = normal.y; + vertices[base + 5u] = normal.z; + + vertices[base + 6u] = tangent.x; + vertices[base + 7u] = tangent.y; + vertices[base + 8u] = tangent.z; + + vertices[base + 9u] = bitangent.x; + vertices[base + 10u] = bitangent.y; + vertices[base + 11u] = bitangent.z; + + vertices[base + 12u] = uv.x; + vertices[base + 13u] = uv.y; +} + +void emitFace(ivec3 voxelPos, int faceIndex) { + uint baseVertex = atomicAdd(counters.vertexCount, VERTICES_PER_FACE); + uint baseIndex = atomicAdd(counters.indexCount, INDICES_PER_FACE); + + if (baseVertex + VERTICES_PER_FACE > MAX_VERTICES || + baseIndex + INDICES_PER_FACE > MAX_INDICES) { + return; + } + + vec3 p = vec3(chunkPos * CHUNK_SIZE + voxelPos); + + vec3 normal; + vec3 tangent; + vec3 bitangent; + + + vec3 v0; + vec3 v1; + vec3 v2; + vec3 v3; + + vec2 uv0; + vec2 uv1; + vec2 uv2; + vec2 uv3; + + if (faceIndex == 0) { + // Top +Y + normal = vec3(0.0, 1.0, 0.0); + tangent = vec3(1.0, 0.0, 0.0); + bitangent = vec3(0.0, 0.0, 1.0); + + v0 = p + vec3(0.0, 1.0, 0.0); + v1 = p + vec3(0.0, 1.0, 1.0); + v2 = p + vec3(1.0, 1.0, 1.0); + v3 = p + vec3(1.0, 1.0, 0.0); + + + uv0 = vec2(0.0, 0.5); + uv1 = vec2(0.0, 1.0); + uv2 = vec2(0.5, 1.0); + uv3 = vec2(0.5, 0.5); + } else if (faceIndex == 1) { + // Bottom -Y + normal = vec3(0.0, -1.0, 0.0); + tangent = vec3(1.0, 0.0, 0.0); + bitangent = vec3(0.0, 0.0, -1.0); + + v0 = p + vec3(0.0, 0.0, 0.0); + v1 = p + vec3(1.0, 0.0, 0.0); + v2 = p + vec3(1.0, 0.0, 1.0); + v3 = p + vec3(0.0, 0.0, 1.0); + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } else if (faceIndex == 2) { + // Right +X + normal = vec3(1.0, 0.0, 0.0); + tangent = vec3(0.0, 0.0, -1.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(1.0, 0.0, 0.0); + v1 = p + vec3(1.0, 1.0, 0.0); + v2 = p + vec3(1.0, 1.0, 1.0); + v3 = p + vec3(1.0, 0.0, 1.0); + + uv0 = vec2(0.0, 0.0); + uv3 = vec2(0.0, 0.5); + uv2 = vec2(0.5, 0.5); + uv1 = vec2(0.5, 0.0); + } else if (faceIndex == 3) { + // Left -X + normal = vec3(-1.0, 0.0, 0.0); + tangent = vec3(0.0, 0.0, 1.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(0.0, 0.0, 0.0); + v1 = p + vec3(0.0, 0.0, 1.0); + v2 = p + vec3(0.0, 1.0, 1.0); + v3 = p + vec3(0.0, 1.0, 0.0); + + uv0 = vec2(0.0, 0.0); + uv1 = vec2(0.0, 0.5); + uv2 = vec2(0.5, 0.5); + uv3 = vec2(0.5, 0.0); + } else if (faceIndex == 4) { + // Front +Z + normal = vec3(0.0, 0.0, 1.0); + tangent = vec3(1.0, 0.0, 0.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(0.0, 0.0, 1.0); + v1 = p + vec3(1.0, 0.0, 1.0); + v2 = p + vec3(1.0, 1.0, 1.0); + v3 = p + vec3(0.0, 1.0, 1.0); + + uv0 = vec2(0.0, 0.0); + uv1 = vec2(0.0, 0.5); + uv2 = vec2(0.5, 0.5); + uv3 = vec2(0.5, 0.0); + } else { + // Back -Z + normal = vec3(0.0, 0.0, -1.0); + tangent = vec3(-1.0, 0.0, 0.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(0.0, 0.0, 0.0); + v1 = p + vec3(0.0, 1.0, 0.0); + v2 = p + vec3(1.0, 1.0, 0.0); + v3 = p + vec3(1.0, 0.0, 0.0); + + uv0 = vec2(0.0, 0.0); + uv1 = vec2(0.0, 0.5); + uv2 = vec2(0.5, 0.5); + uv3 = vec2(0.5, 0.0); + } + + writeVertex(baseVertex + 0u, v0, normal, tangent, bitangent, uv0); + writeVertex(baseVertex + 1u, v1, normal, tangent, bitangent, uv1); + writeVertex(baseVertex + 2u, v2, normal, tangent, bitangent, uv2); + writeVertex(baseVertex + 3u, v3, normal, tangent, bitangent, uv3); + + indices[baseIndex + 0u] = baseVertex + 0u; + indices[baseIndex + 1u] = baseVertex + 1u; + indices[baseIndex + 2u] = baseVertex + 2u; + + indices[baseIndex + 3u] = baseVertex + 0u; + indices[baseIndex + 4u] = baseVertex + 2u; + indices[baseIndex + 5u] = baseVertex + 3u; + + atomicAdd(drawCmd.indexCount, INDICES_PER_FACE); +} + +void main() { + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + + if (pos.x >= CHUNK_SIZE || pos.y >= CHUNK_SIZE || pos.z >= CHUNK_SIZE) { + return; + } + + uint current = getVoxel(pos); + + if (current == 0u) { + return; + } + + if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0); + if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1); + if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2); + if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3); + if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4); + if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5); +} \ No newline at end of file diff --git a/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl b/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl new file mode 100644 index 0000000..eeb73a7 --- /dev/null +++ b/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl @@ -0,0 +1,285 @@ +#version 460 + +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +const int CHUNK_SIZE = 16; +const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; +const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; + +const uint FLOATS_PER_VERTEX = 14u; +const uint VERTICES_PER_FACE = 4u; +const uint INDICES_PER_FACE = 6u; + +const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * 12); +const uint MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * VERTICES_PER_FACE; +const uint MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * INDICES_PER_FACE; + +layout(std430, binding = 0) readonly buffer VoxelData { + uint voxels[]; +}; + +layout(std430, binding = 1) buffer VertexBuffer { + float vertices[]; +}; + +layout(std430, binding = 2) buffer IndexBuffer { + uint indices[]; +}; + +struct DrawCommand { + uint indexCount; + uint instanceCount; + uint firstIndex; + int vertexOffset; + uint firstInstance; +}; + +layout(std430, binding = 3) buffer DrawCommands { + DrawCommand drawCmds[]; +}; + +layout(push_constant) uniform ChunkInfo { + ivec3 chunkPos; + int slot; + uint vertexFloatOffset; + uint indexOffset; + uint indirectCommandIndex; + uint padding0; +}; + + +layout(std430, binding = 4) buffer Counters { + uint vertexCount; + uint indexCount; +} counters; + + +uint flatten(ivec3 pos) { + return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z); +} + +uint getVoxel(ivec3 pos) { + if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0; + if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0; + if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0; + + return voxels[flatten(pos)]; +} + +void writeVertex(uint vertexIndex, vec3 position, vec3 normal, vec3 tangent, vec3 bitangent, vec2 uv) { + uint base = vertexFloatOffset + vertexIndex * FLOATS_PER_VERTEX; + + vertices[base + 0u] = position.x; + vertices[base + 1u] = position.y; + vertices[base + 2u] = position.z; + + vertices[base + 3u] = normal.x; + vertices[base + 4u] = normal.y; + vertices[base + 5u] = normal.z; + + vertices[base + 6u] = tangent.x; + vertices[base + 7u] = tangent.y; + vertices[base + 8u] = tangent.z; + + vertices[base + 9u] = bitangent.x; + vertices[base + 10u] = bitangent.y; + vertices[base + 11u] = bitangent.z; + + vertices[base + 12u] = uv.x; + vertices[base + 13u] = uv.y; +} + +void emitFace(ivec3 voxelPos, int faceIndex, uint VoxelType) { + uint localBaseVertex = atomicAdd(counters.vertexCount, VERTICES_PER_FACE); + uint localBaseIndex = atomicAdd(counters.indexCount, INDICES_PER_FACE); + + if (localBaseVertex + VERTICES_PER_FACE > MAX_VERTICES || + localBaseIndex + INDICES_PER_FACE > MAX_INDICES) { + return; + } + + uint baseVertex = localBaseVertex; + uint baseIndex = indexOffset + localBaseIndex; + + vec3 p = vec3(chunkPos * CHUNK_SIZE + voxelPos); + + vec3 normal; + vec3 tangent; + vec3 bitangent; + + + vec3 v0; + vec3 v1; + vec3 v2; + vec3 v3; + + vec2 uv0; + vec2 uv1; + vec2 uv2; + vec2 uv3; + + if (faceIndex == 0) { + // Top +Y + normal = vec3(0.0, 1.0, 0.0); + tangent = vec3(1.0, 0.0, 0.0); + bitangent = vec3(0.0, 0.0, 1.0); + + v0 = p + vec3(0.0, 1.0, 0.0); + v1 = p + vec3(0.0, 1.0, 1.0); + v2 = p + vec3(1.0, 1.0, 1.0); + v3 = p + vec3(1.0, 1.0, 0.0); + + if(VoxelType == 1) { + uv0 = vec2(0.0, 0.5); + uv1 = vec2(0.0, 1.0); + uv2 = vec2(0.5, 1.0); + uv3 = vec2(0.5, 0.5); + } else{ + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } + } else if (faceIndex == 1) { + // Bottom -Y + normal = vec3(0.0, -1.0, 0.0); + tangent = vec3(1.0, 0.0, 0.0); + bitangent = vec3(0.0, 0.0, -1.0); + + v0 = p + vec3(0.0, 0.0, 0.0); + v1 = p + vec3(1.0, 0.0, 0.0); + v2 = p + vec3(1.0, 0.0, 1.0); + v3 = p + vec3(0.0, 0.0, 1.0); + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } else if (faceIndex == 2) { + // Right +X + normal = vec3(1.0, 0.0, 0.0); + tangent = vec3(0.0, 0.0, -1.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(1.0, 0.0, 0.0); + v1 = p + vec3(1.0, 1.0, 0.0); + v2 = p + vec3(1.0, 1.0, 1.0); + v3 = p + vec3(1.0, 0.0, 1.0); + if(VoxelType == 1) { + + uv2 = vec2(0.0, 0.0); + uv3 = vec2(0.0, 0.5); + uv0 = vec2(0.5, 0.5); + uv1 = vec2(0.5, 0.0); + } else{ + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } + } else if (faceIndex == 3) { + // Left -X + normal = vec3(-1.0, 0.0, 0.0); + tangent = vec3(0.0, 0.0, 1.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(0.0, 0.0, 0.0); + v1 = p + vec3(0.0, 0.0, 1.0); + v2 = p + vec3(0.0, 1.0, 1.0); + v3 = p + vec3(0.0, 1.0, 0.0); + + if(VoxelType == 1) { + + uv3 = vec2(0.0, 0.0); + uv0 = vec2(0.0, 0.5); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(0.5, 0.0); + } else{ + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } + } else if (faceIndex == 4) { + // Front +Z + normal = vec3(0.0, 0.0, 1.0); + tangent = vec3(1.0, 0.0, 0.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(0.0, 0.0, 1.0); + v1 = p + vec3(1.0, 0.0, 1.0); + v2 = p + vec3(1.0, 1.0, 1.0); + v3 = p + vec3(0.0, 1.0, 1.0); + + if(VoxelType == 1) { + + uv3 = vec2(0.0, 0.0); + uv0 = vec2(0.0, 0.5); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(0.5, 0.0); + } else{ + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } + } else { + // Back -Z + normal = vec3(0.0, 0.0, -1.0); + tangent = vec3(-1.0, 0.0, 0.0); + bitangent = vec3(0.0, 1.0, 0.0); + + v0 = p + vec3(0.0, 0.0, 0.0); + v1 = p + vec3(0.0, 1.0, 0.0); + v2 = p + vec3(1.0, 1.0, 0.0); + v3 = p + vec3(1.0, 0.0, 0.0); + + if(VoxelType == 1) { + + uv2 = vec2(0.0, 0.0); + uv3 = vec2(0.0, 0.5); + uv0 = vec2(0.5, 0.5); + uv1 = vec2(0.5, 0.0); + } else{ + uv0 = vec2(0.5, 0.0); + uv1 = vec2(0.5, 0.5); + uv2 = vec2(1.0, 0.5); + uv3 = vec2(1.0, 0.0); + } + } + + writeVertex(baseVertex + 0u, v0, normal, tangent, bitangent, uv0); + writeVertex(baseVertex + 1u, v1, normal, tangent, bitangent, uv1); + writeVertex(baseVertex + 2u, v2, normal, tangent, bitangent, uv2); + writeVertex(baseVertex + 3u, v3, normal, tangent, bitangent, uv3); + + indices[baseIndex + 0u] = baseVertex + 0u; + indices[baseIndex + 1u] = baseVertex + 1u; + indices[baseIndex + 2u] = baseVertex + 2u; + + indices[baseIndex + 3u] = baseVertex + 0u; + indices[baseIndex + 4u] = baseVertex + 2u; + indices[baseIndex + 5u] = baseVertex + 3u; + + atomicAdd(drawCmds[indirectCommandIndex].indexCount, INDICES_PER_FACE); +} + +void main() { + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + + if (pos.x >= CHUNK_SIZE || pos.y >= CHUNK_SIZE || pos.z >= CHUNK_SIZE) { + return; + } + + uint current = getVoxel(pos); + + if (current == 0u) { + return; + } + + if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0,current); + if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1,current); + if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2,current); + if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3,current); + if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4,current); + if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5,current); +} \ No newline at end of file diff --git a/resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl b/resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl new file mode 100644 index 0000000..91747c9 --- /dev/null +++ b/resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl @@ -0,0 +1,27 @@ +#version 460 + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(std430, binding = 0) buffer DrawCommand { + uint indexCount; + uint instanceCount; + uint firstIndex; + int vertexOffset; + uint firstInstance; +} drawCmd; + +layout(std430, binding = 1) buffer Counters { + uint vertexCount; + uint indexCount; +} counters; + +void main() { + drawCmd.indexCount = 0u; + drawCmd.instanceCount = 1u; + drawCmd.firstIndex = 0u; + drawCmd.vertexOffset = 0; + drawCmd.firstInstance = 0u; + + counters.vertexCount = 0u; + counters.indexCount = 0u; +} \ No newline at end of file diff --git a/resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl b/resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl new file mode 100644 index 0000000..fab801d --- /dev/null +++ b/resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl @@ -0,0 +1,42 @@ +#version 460 + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +const uint FLOATS_PER_VERTEX = 14u; + +struct DrawCommand { + uint indexCount; + uint instanceCount; + uint firstIndex; + int vertexOffset; + uint firstInstance; +}; + +layout(std430, binding = 0) buffer DrawCommands { + DrawCommand drawCmds[]; +}; + +layout(std430, binding = 1) buffer Counters { + uint vertexCount; + uint indexCount; +} counters; + +layout(push_constant) uniform ChunkInfo { + ivec3 chunkPos; + int slot; + uint vertexFloatOffset; + uint indexOffset; + uint indirectCommandIndex; + uint padding0; +}; + +void main() { + drawCmds[indirectCommandIndex].indexCount = 0u; + drawCmds[indirectCommandIndex].instanceCount = 1u; + drawCmds[indirectCommandIndex].firstIndex = indexOffset; + drawCmds[indirectCommandIndex].vertexOffset = int(vertexFloatOffset / FLOATS_PER_VERTEX); + drawCmds[indirectCommandIndex].firstInstance = 0u; + + counters.vertexCount = 0u; + counters.indexCount = 0u; +} \ No newline at end of file diff --git a/resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl b/resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl new file mode 100644 index 0000000..e721a1d --- /dev/null +++ b/resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl @@ -0,0 +1,201 @@ +#version 460 +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +const int CHUNK_SIZE = 16; +const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; + +// A 1D storage buffer representing a flat 3D array of voxel IDs +layout(std430, binding = 0) buffer VoxelData { + uint voxels[]; +}; + +layout(push_constant) uniform ChunkOffset { + ivec3 chunkPos; + int padding0; +}; +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : stegu +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com + +vec4 permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); } +vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } + +float simplex_noise(vec3 v) { + const vec2 C = vec2(1.0/6.0, 1.0/3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = mod(i, 289.0); + vec4 p = permute(permute(permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0)) + + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + + i.x + vec4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + // Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + + // Returns a value scaled exactly between -1.0 and 1.0 + return 42.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3))); +} +float noise2D(vec2 p) { + return simplex_noise(vec3(p.x, p.y, 0.0)); +} + +float fbm(vec2 p, int octaves, float lacunarity, float gain) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + float amplitudeSum = 0.0; + + for (int i = 0; i < octaves; i++) { + value += noise2D(p * frequency) * amplitude; + amplitudeSum += amplitude; + + frequency *= lacunarity; + amplitude *= gain; + } + + return value / amplitudeSum; +} + +float ridgedFbm(vec2 p, int octaves, float lacunarity, float gain) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + float amplitudeSum = 0.0; + + for (int i = 0; i < octaves; i++) { + float n = noise2D(p * frequency); + n = 1.0 - abs(n); + n = n * n; + + value += n * amplitude; + amplitudeSum += amplitude; + + frequency *= lacunarity; + amplitude *= gain; + } + + return value / amplitudeSum; +} + +vec2 domainWarp(vec2 p) { + float wx = fbm(p + vec2(17.31, 91.73), 3, 2.0, 0.5); + float wz = fbm(p + vec2(43.17, 12.89), 3, 2.0, 0.5); + + return p + vec2(wx, wz) * 35.0; +} + +float terrainHeight(vec2 worldXZ) { + vec2 p = worldXZ; + + vec2 warped = domainWarp(p * 0.006); + + float continent = fbm(warped * 0.45, 5, 2.0, 0.5); + continent = continent * 0.5 + 0.5; + + float hills = fbm(p * 0.025, 5, 2.0, 0.48); + float detail = fbm(p * 0.09, 3, 2.1, 0.45); + + float mountainMask = smoothstep(0.52, 0.82, continent); + float mountains = ridgedFbm(warped * 1.15, 5, 2.0, 0.52); + + float height = 18.0; + height += continent * 28.0; + height += hills * 14.0; + height += detail * 3.0; + height += mountainMask * mountains * 55.0; + + return height; +} + +void main() { + ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz); + + if (localPos.x >= CHUNK_SIZE || localPos.y >= CHUNK_SIZE || localPos.z >= CHUNK_SIZE) { + return; + } + + ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos; + + float height = terrainHeight(vec2(worldPos.x,worldPos.z) * 0.02) * 0.0015 + 10 ; + + uint voxelType = 0u; + + if (float(worldPos.y) <= height) { + float depthBelowSurface = height - float(worldPos.y); + + if (depthBelowSurface < 1.5) { + voxelType = 1u; // Grass/topsoil + } else if (depthBelowSurface < 5.0) { + voxelType = 2u; // Dirt + } else { + voxelType = 3u; // Stone + } + } + + uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z); + voxels[index] = voxelType; +} \ No newline at end of file diff --git a/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl b/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl new file mode 100644 index 0000000..bfcebc6 --- /dev/null +++ b/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl @@ -0,0 +1,260 @@ +#version 460 +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +const int CHUNK_SIZE = 16; +const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; + +// A 1D storage buffer representing a flat 3D array of voxel IDs +layout(std430, binding = 0) buffer VoxelData { + uint voxels[]; +}; + +layout(push_constant) uniform ChunkOffset { + ivec3 chunkPos; + int slot; + uint vertexFloatOffset; + uint indexOffset; + uint indirectCommandIndex; + uint padding0; +}; +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : stegu +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com + +vec4 permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); } +vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } + +float simplex_noise(vec3 v) { + const vec2 C = vec2(1.0/6.0, 1.0/3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = mod(i, 289.0); + vec4 p = permute(permute(permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0)) + + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + + i.x + vec4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + // Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + + // Returns a value scaled exactly between -1.0 and 1.0 + return 42.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3))); +} +float noise2D(vec2 p) { + return simplex_noise(vec3(p.x, p.y, 0.0)); +} + +float fbm(vec2 p, int octaves, float lacunarity, float gain) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + float amplitudeSum = 0.0; + + for (int i = 0; i < octaves; i++) { + value += noise2D(p * frequency) * amplitude; + amplitudeSum += amplitude; + + frequency *= lacunarity; + amplitude *= gain; + } + + return value / amplitudeSum; +} + +float ridgedFbm(vec2 p, int octaves, float lacunarity, float gain) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + float amplitudeSum = 0.0; + + for (int i = 0; i < octaves; i++) { + float n = noise2D(p * frequency); + n = 1.0 - abs(n); + n = n * n; + + value += n * amplitude; + amplitudeSum += amplitude; + + frequency *= lacunarity; + amplitude *= gain; + } + + return value / amplitudeSum; +} + +vec2 domainWarp(vec2 p) { + float wx = fbm(p + vec2(17.31, 91.73), 3, 2.0, 0.5); + float wz = fbm(p + vec2(43.17, 12.89), 3, 2.0, 0.5); + + return p + vec2(wx, wz) * 35.0; +} + +float terrainHeight(vec2 worldXZ) { + vec2 p = worldXZ; + + vec2 warped = domainWarp(p * 0.004); + + float broad = fbm(warped * 0.45, 5, 2.0, 0.5); + broad = broad * 0.5 + 0.5; + + float hills = fbm(p * 0.025, 4, 2.0, 0.48); + float detail = fbm(p * 0.085, 2, 2.0, 0.4); + + float height = 8.0; + height += broad * 12.0; + height += hills * 6.0; + height += detail * 2.0; + + return clamp(height, 4.0, 28.0); +} + +float rand(vec2 co) { + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453123); +} +float fbm3D(vec3 p, int octaves, float lacunarity, float gain) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + float amplitudeSum = 0.0; + + for (int i = 0; i < octaves; i++) { + value += simplex_noise(p * frequency) * amplitude; + amplitudeSum += amplitude; + + frequency *= lacunarity; + amplitude *= gain; + } + + return value / amplitudeSum; +} +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + float a = rand(i); + float b = rand(i + vec2(1.0, 0.0)); + float c = rand(i + vec2(0.0, 1.0)); + float d = rand(i + vec2(1.0, 1.0)); + + vec2 u = f * f * (3.0 - 2.0 * f); + + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; +} + +vec2 randG(vec2 p) { + p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); + return -1.0 + 2.0 * fract(sin(p) * 43758.5453123); +} + +float perlinNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0); + + float dotTopLeft = dot(randG(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)); + float dotTopRight = dot(randG(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)); + float dotBottomLeft = dot(randG(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)); + float dotBottomRight = dot(randG(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)); + + return mix(mix(dotTopLeft, dotTopRight, u.x), + mix(dotBottomLeft, dotBottomRight, u.x), u.y); +} + +void main() { + ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz); + ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos; + + float height = valueNoise(vec2(worldPos.x, worldPos.z) * 0.005) * 100 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.01) * 10 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.1) * 5+ valueNoise(vec2(worldPos.x, worldPos.z)) * 0.5; + //height = clamp(height, 4.0, 28.0); + + uint voxelType = 0u; + + if (float(worldPos.y) <= height && float(floor(worldPos.y/CHUNK_SIZE) * CHUNK_SIZE + CHUNK_SIZE * 2) >= height) { + float depthBelowSurface = height - float(worldPos.y); + + if (depthBelowSurface < 1.5) { + voxelType = 1u; // Grass/topsoil + } else if (depthBelowSurface < 5.0) { + voxelType = 2u; // Dirt + } else { + voxelType = 3u; // Stone + } + } + +// if (voxelType != 0u && worldPos.y < int(height) - 6) { +// float cave = fbm3D(vec3(worldPos) * 0.045, 4, 2.0, 0.5); +// +// if (cave > 0.42) { +// voxelType = 0u; +// } +// } + + uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z); + voxels[index] = voxelType; +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/forward_skybox_fragment.glsl.spv b/resources/EngineResources/shaders/forward_skybox_fragment.glsl.spv deleted file mode 100644 index c62d0b986638909981a443c1e157ed4890f3b17f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 780 zcmYk3O-lk{6oqeor9pQ zciwx>d*1ss@z{CVY|C=CYsa>Z z54qTu7v%-%;8j3TTv^S&^(bLkb6T#`Zab|fw>KKOlj$Px+`u1tZr>k!y{Z4{q04OO z{9!Mc^*04cDK_gSEg97gXVYdFgkzNxlhR~nlaIxFIPY`^qrl?=o*t!r_2$hm9QP-J z<|rfmp8{lH-q$1akI#gehkNp@^(C?J^=RUyrmQ$6t|qTY&pyEPUehEkKQqQ`Vo`Vc`uee_TNe(5|_o7026WRij>2&U^ISGs}ZIXUE+AD#NY(58$>t1poj5 diff --git a/resources/EngineResources/shaders/lighting_frag.glsl b/resources/EngineResources/shaders/lighting_frag.glsl index 515758c..7a5f481 100644 --- a/resources/EngineResources/shaders/lighting_frag.glsl +++ b/resources/EngineResources/shaders/lighting_frag.glsl @@ -139,8 +139,6 @@ void main() { float emissiveness = emissive.r; float ssao = texture(ssaoBlur, inTextCoord).r; - outFragColor = vec4(vec3(normalW.a/2.0,normalW.a/2.0,normalW.a/2.0), 1); - return; float roughness = pbr.g; float metallic = pbr.b; diff --git a/resources/EngineResources/shaders/lighting_frag.glsl.spv b/resources/EngineResources/shaders/lighting_frag.glsl.spv deleted file mode 100644 index 2fdb0982c56546233dc72a0ea79219483f3f7f14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13336 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 N_@VQ+6F7H({{bigH=zIk diff --git a/resources/EngineResources/shaders/multi-sampled_post_process_frag.glsl.spv b/resources/EngineResources/shaders/multi-sampled_post_process_frag.glsl.spv deleted file mode 100644 index 2b3bfbeb89e7d5c33eca5c975313d14c42990fc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3704 zcmZ9Nd2^IS5XL8j4fiECC?=pn6^9VRWjGQe1T+{hinr^MY+yCJ8+SJm@CqV=2i~8; z|NIJmD6c9lf4|M!#cQUj)BQZ%)AP*iypzsFyOyNXkyfNt>E|>*)}=)-Dd~IhD^gb* z508wE9B8&C4)h&9XyxkEscYxfq$O!Fu~scrYVxmQlh|77fIT%4#h%HyrdY}vY{xw=Yid}?MQUr?YTziuHF(45lM zQngyzGdtPWpI}@qrSbYyy@4;FW(&UBES2_D4)r&CFC6Nho$RHQTp?}5H%ry&sq#>L zrq*h6o8VgI>#dna`MevnZZrNRxS@KzF_Cfm@za&-<*7E=Y}XxzYp*>vQzeA!Ovmt* zc3en9_*hSc_Pz|au#ab2sXbV+z;E+NfC51Wfg9Z501$b@&zPkY5TY$g*A1Z$a=A8Exry2?R+V!! z+l)F2=_hfnZWwLue}{z(v3u`nqX&3r4toY2IqZFWFu$|CuJ`d=PQ$KTy&CfU#rC)7 zdTz3Fd)l`;wc}01U2xslX7qXI#oo_u{w~GKX+7X&SuDR1yb9lq+28urcx&aiQoROm zKl3q+18-;jwP5R;_h9yMeb3VM?dLjs@$NPB?ISiXAL||=cI+c#?kFagH*4*4 z9CK`-;~+lx3&b6m8eYj_&!9iU-ZS%J&%t}<=*{|;=3(kX`5^HX>=#VlHSOz%=swkG zAMs?y#k}{xF;7jQ&o|05h`MI3&Ro>pBzBFc`!H8$F6urZ_6|nf?OdI?sQZH0yD0WI z`4(dg2L5gyp9uW@JU+Pt6@J5>p?m)kuYNiAF814zJHof7SC2#ef5H^-*7}=Y#^T(( zi?ccGo%D^$=Y69Bo1e>J=ikj?^S)70?|yxw#3xzbJ-mi_2gH6mZ(!bm39#SRn;CZv z?A?4T5^Vl|1? za1FChX!L)JHAQyj-rmLJtQ)|*r>^atH1`+%V;#L(s(6Q5ysJ}~oLY=SON}_Mr4G(( znFd=ETHYs?vu*&(YcZ#mSVymx8N5R+O?(TJQ;V^C@t!m=b$RaBF@HyM-Wl=n>^yD| zZ^4|ScJpx_=F|}V^=kMS?@)u^+DDk28jPLqUG$p@4Y!Cx!yK_VG<-&^2Ir_@4hs$D z)DZpkYPf@UsNpvLb4*SR#?HTs_gfAPUlNA~@4h%Rd_}AV=cvJaXfUUS=&!e@_vstV zyJM~2kN7zE-Q0a_1tuT8&@HSGjL6F|Dsf%KL^j>;s0OH!8dDT7O%r^%3|NH&6wx26(8^Aeqz@adxnQ| z*j~qS*!)n2<9-|f+gI#+_ax?;@s=FSxOndlf#u@8>m`=Af?*mL}q-*piG3}(#$=JzA+ z$Lwt{<2Zw7i9G}HUi=wM-O>9jv1`Q{4HG*j-netba?TsTtarbjy*c~%o1Mqx0zXIW zncT|0k>`o!tc&xK^9(!>b?Zad2(h~6nD3dqfXQ9JoNrDpf5!7?JFjPyoa;xwi^QIx ezjYV>5+)b-{l$!v54)FXAA_@>HQsx%_x?ZDNJhK> diff --git a/resources/EngineResources/shaders/post_process_frag.glsl.spv b/resources/EngineResources/shaders/post_process_frag.glsl.spv deleted file mode 100644 index ad42b726b2c30f8f7394e230ccd37af6145095d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6860 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 0 && material.OpacityMapIdx < MAX_TEXTURES){ + vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0); + + if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) { + Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0); + } + + if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) { Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords); } diff --git a/resources/EngineResources/shaders/scene_fragment.glsl.spv b/resources/EngineResources/shaders/scene_fragment.glsl.spv deleted file mode 100644 index a05b0b0cd262a19b3b890926e90f499dabf6294f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6344 zcma);i+5aA6^Cz|2N9&DJVj_tC<;ogRe32=Qc9bmDJg9cv}k5JnWQ6=J7H!5t)isJ z%eUYQ-*2smfTDm4ABYujE&Ov_K9;WK_uYGUa+@__dAoMc-oL$n`|NYhK4;RmdgDn+ zvMM+2G++?SFq*)oitM z-(co*U5Bcj{q@7$`8M+o^3Och+s(o2rw%XWayN*-q1B$PHg{L&Fc;^so-`a8YboDA z&fD9XpE)Eg<{1QU7oe1=*?r6KwBG6Ltk$}e9ljxav-NJZ*=*Db*P_qb>$8nchh22B z^Q<;_C*z~`9fdoqK76N?csPnR4`qAt+MKt)T}?a9`C2`#9VxiE|5W_l6P+jU*DUid zuX$~re`2m$YjpF}i#4ByZ^@BwYSg@L$rmZMK zH^f)!4Sg&1hQ40CA>OMu#8>JKeJk~bzLk1I-%7oqZ>8SQr+9x(Jbr5*%6zZZ8**Q* zH}tR68~Rr24Sl_PV=$X9`rxLtG0k z=U8`Nb#|^l4IDd{E|(hW--SZ8|j{wBx8KT z8)^Q$p=OwGI{B;VOg-%um~VU|y|%&9GISS_?z`W{d`JTG9*Mb^fq93-&MaYl1@^iU z=DjiQ{1WDU5gRUH-W9P6OPKdW?BWvU{Sez!!n_w^TS}PsL2R^yc@M;{D`Bo#Y*z`h z=f%cLn0+p`r-a$tV*5*&dn9&C3A2~QZbim8SM$5xN@n+EJ>7@C3!n4&#U6$&-*1fm zbq@XJQXfJ5!oC3A^D)-`R`=Z0{meCr7++!BfcR82X2@*& zPrp5*-`>;C>*>$_w$L`;8KB}LSla4mqq#T3$T{%s0d40yi~l|UVZ?6(-RIdGBi>8o zD!pRFgQGr7e*4B)^P1oO=*2Db{@?uTS(|5X&JF0Et+w;pORit+s>1ec#ay>NG>oi5 zE-CEO(f!Qj*;i|sttrGGu6YgS^eVRYx#Kf)M$68;Op z%n|lQ=$>iVZ$bAA!+tBe??BjF(A~$d--+%V&Ua~{m;G0OS%1X88{PGVeKopg8TKf; z_do3I=&m>Ho#>uL*w>?b7GaO0dq!bTpnE=H??ungs6TrTtX(_&A4GS9&g8!XsIF_0 z(LFNObJDILv2U)oiujpF`(S1*T(b$5yc%MRqE9i_y_rE)A?LC)O-A|Jm~|G1 zaluawq~`O<*Fx1VX6x;euC2)bX`kE5Gk+qkEYBpDqI`)RDdz4FRd>v;~{n8^QUbmxw<(DrQ;bN;^+ zx;*REezCy9ercKga$#Rir(2i(@8_KV1hN0++Nbtr%)KAozca%2KKi#r*Z-aBG&k zl@)0lC&#(ofXH$G#m+^gWc5nYb&iyUp^g7YSHIqqq2E=HGg z5h6$1xZu1QU5@7woJ-K<_)f{uHZC}u(B*h$!P$&1$G1$5wsFCE8@e3(EI4mRm$L5wwEDtd=uqp8yB3*(dD@B!MPG$&J~CpZR6ya`(20}-%L54=~ajv z-%>f+#>INxgD%H@jrD9rm*aaYN87mIT!SvhnBZ(H>`_KJ+QtRvT68(~VsNfQH^+8F zj<#{Z*?}&{H#|6F=yG-_y~g8y7j>kFMXl5_kS)bn(0B zc5~f=h{^Yj(Kc4!2N1C**oy;5d!;F6aCSKo%5Ha5}b#qo2Ysi1O`QrMc zzB;<~4I@$CG`jes#hi!G#byxa{0O6;bLwj#A4kls9=Y4-%h%ok6E~*IIFHKB5 z;KA1}^UWjw9>z~1733%)-yXgf5s#Sr&?`te=6-DPhfM{|!beigAs@4o9FV*DB+{#dd8 zuNT-OjIRHijDD_P-!~93*RLMAzlCmY--yWlZFKP`i`?Hq7fTUqj69Bi=Ohm>eiv~b z>o(pwtmFHPe%4{k_Yg7bP>(u(fWEwrAA*S+@eAyEbTPSs c{i(pr6?f 0 && material.OpacityMapIdx < MAX_TEXTURES){ + vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0); + + if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) { + Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0); + } + + if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) { Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords); } + outOpacity = Opacity; float opacityf = Opacity.x + Opacity.y + Opacity.z; diff --git a/resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv b/resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv deleted file mode 100644 index 072261923e1172b4963695e3189b2d5422d5a135..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11428 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 W$Sd!;jXigayk~>W`ycFLd+dKhcdf4g diff --git a/resources/EngineResources/shaders/scene_opaque_fragment.glsl b/resources/EngineResources/shaders/scene_opaque_fragment.glsl index 17d2403..8bf5bc4 100644 --- a/resources/EngineResources/shaders/scene_opaque_fragment.glsl +++ b/resources/EngineResources/shaders/scene_opaque_fragment.glsl @@ -65,11 +65,16 @@ void main() } else{ outAlbedo = material.diffuseColor; } - vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1); - if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1); - if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){ + vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0); + + if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) { + Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0); + } + + if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) { Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords); } + float opacityf = Opacity.x + Opacity.y + Opacity.z; opacityf = opacityf/3; if(opacityf < 0.9){discard;} diff --git a/resources/EngineResources/shaders/scene_opaque_fragment.glsl.spv b/resources/EngineResources/shaders/scene_opaque_fragment.glsl.spv deleted file mode 100644 index 156f36fa33551b58fba98d0bb88517c7e1a400a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6344 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 diff --git a/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl b/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl index 8a14dc0..5d79877 100644 --- a/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl +++ b/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl @@ -94,9 +94,13 @@ void main() outAlbedo = material.diffuseColor; } - vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1); - if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1); - if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){ + vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0); + + if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) { + Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0); + } + + if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) { Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords); } outOpacity = Opacity; diff --git a/resources/EngineResources/shaders/scene_translucent_fragment.glsl b/resources/EngineResources/shaders/scene_translucent_fragment.glsl index a7c138a..f646f6c 100644 --- a/resources/EngineResources/shaders/scene_translucent_fragment.glsl +++ b/resources/EngineResources/shaders/scene_translucent_fragment.glsl @@ -64,9 +64,13 @@ void main() } else{ outAlbedo = material.diffuseColor; } - vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1); - if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1); - if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){ + vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0); + + if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) { + Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0); + } + + if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) { Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords); } diff --git a/resources/EngineResources/shaders/scene_translucent_fragment.glsl.spv b/resources/EngineResources/shaders/scene_translucent_fragment.glsl.spv deleted file mode 100644 index da41461012ce83fd19c3f31ddd0ddd74e737260b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6344 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 0 && material.OpacityMapIdx < MAX_TEXTURES){ + vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0); + + if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) { + Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0); + } + + if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) { Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords); } outOpacity = Opacity; diff --git a/resources/EngineResources/shaders/scene_vertex.glsl.spv b/resources/EngineResources/shaders/scene_vertex.glsl.spv deleted file mode 100644 index 4a1d6a1e1d9547b779ce6ff4c09ccb45e24ec1b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3264 zcmZ9OYj+c65XT?dq@dhHUy@jIms5#SAGTk zNPa5ccn<&H?lb9g@^B_I^PkHzGdsIYQ>jLY%OdGfT268GaX~@20(OJlc*&MXZXe zyx<&c`8X+(Jd^j~(w}Ei;z?F)B!4pAiH#Y{wwflxI|&y@@x;ax#kQZO6C3^T3_0|> zEZ!aEzuOF$6&NR+)rZoDfgim!@wu-F_ftjH%Du?jl+N?y4tB}zu)VT7 zOb_ocEWCsLqHYd3*`q3Fy_CVNUTVkA{a|pzhyi0~3_}Lvog??MxYdiyv3gAp>oqK_ zmpuw+g1$&19cIS2<)EKhxkKpH%xdK~C)BsRKXnn$-e5PK?-Dw_U}slCJ@R_hW3Ai| z?C7VJg**$2CLZ~$q&e}1=$yRh7ajle`aL2JhThQc3*y9rU-LS<1~#wXquz$^G0EHk zhA%oh1a?OH3Gs%ASuA_~q+|~9>>|G0g??I`S|ILXf6R7PGPQwm7dqcCFk;Vp8GrhG zU7S9t8~X+ELn3hE(b+{XYQy(Uk#m3Dr1rNZHBfc1qrW4<|AO>)#fbr%mvm8_y1}qP z-20w5HDKpnbiQXcPj=3F{6I4E0K*rZeFG!cSK`ER56|v~IQ>|UH@yvLRe{l1rN z2IzeAh_{*Wy`x8T?Cfi3XJ146&Xk>f#m+P6i!%?a|5wT60w+Iu*dWY5v@XP;gb zv16hCYaS<_Ir8qYN9&5A*M2X1rtO!D*`E(rs-xXY4>1-IE; zksQwEbLn6lo5NMfVBu`O@K`vTFNG10KlX4o*Q9elKGe+KUl;M7F%Ra2j-T~(OY(G2 zw@Z6f8#7-OfpI#T4$u3J2pr;2H+9kvF?U78fLqMh9>>O+j%f)ahCCLtCK(*!SWH)2 z#{2z^h+4>v?=g>mD;eKK5k8yRQ~bXZVPh6euk)O!`JRY5pqlh51_R^vvh}uZZX269(%fXyk42_OBqv+S`Q?&^?zfr*p zckVmqojLd3S1jCB%#N&Xr*>}JXj?&yi7V&T^+sMl&4T{J<2{Oo6>}k)rd6z@N>0bo zjEiGsTiKEhUJZ0A%GK;gKb5RzuIIbMq3gZ-llk0FvrQcOaWo74AX*iu&-lI-aA=lgCtHCYA2?w&CJs8%~!G>ji>WCRVOiMd4p|m>J-% zG)+wv{r1&$*ahmfEH&yq3=v%^g!J`MW6Wo(tihY=sV1{2Y jj_RvedNh>ygYh_1^8cq)?9@@Bfq#<&yTSdb!?W@q!Ob@1 diff --git a/resources/EngineResources/shaders/skybox_vertex.glsl.spv b/resources/EngineResources/shaders/skybox_vertex.glsl.spv deleted file mode 100644 index bf0a2ce9176e5839dfbcdf450a2b80e38da27ee8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2452 zcmZ9NYm*aI5QfhtBp?WgD;E{l?5=loy#b=gb%CrJO;#+vrf_$#Mq`r71;J1L1^r3> zD!*9e^UO@MQ#RGx-EUt{pEIG^*gTxlN;;N~r|(lqr&0qXfwc?S?cMKf%@_My7cYHe z#EH}_0*yJDjuiSK{{H$fA8R}ZAA|40P5w2Ie-nHt9ZlWdu-or)9G-&csk04 zqkNnV_w!k{x5yu7#vQ4}<>S54a=#wXBBI`}#hmt>EEhjyPqrtM+5Q|ewfN^8`FJpy z=Zk#8bmqPQHvi@6gFO4Kh&hF=aeMjbQ8r6dYb7!1u|be|tH|Y#lPa&7KEa+&=J*b$ zPtgan$@a$SUGEWCy@z|Q z_t3V7WDoaP_GlHlxM!7|Tfg&&DFZV{tXad<#eAEqR5fOu2yyi@Xl-N%K1-CdYwPb| z`z5K1U#)EKA^b5O9b)?Tf! z)7USecVPQpsO;0|lKE$l=3CF+FC*>c?8ZCSI-JrUH^Sa1>@xpjbmN`Z*}Th`?IOCh z#hgvsdlYlFo5&6S@5nc&FW%8*bib|oJNgV;Jl@q6bo2h=U0M5c z*ckD6t6!k|R((g_<5gHp3hYaCv2tH!+_eg8AY&ib(akqrzvue1deb-1?Qe|d@tYBI z4)@%J#ro{w9&)F`#3g%scE88xw`|j5Ok6SXPNUU09>m`9>DdX2Mav~ZG!>h%ygc^S z4!Q)EWgD_3>EP8sUpZAZ`&Lrk=FDlhPP6GW?%YnV=MLh}(09Y2>$_gi_d9X$?xQPB z=z?x19D0+2f)tZ|!L#bo4qtpPGAn5Q@))<;Z@tj(3m5cb#-RJ;f5f*@)b|oCGe^Vt zzTbYmjlu}2IjTvGeSltu4@NM-)XHv0oH`ktQan#}C$=3JMh54k)vKVk~<nW3HZZ)X8+)DM#H0RbrMM8Tsgm Pvo}4t2eDsGav}Qzz^g!t diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java index fbd0a2e..8703583 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java @@ -5,6 +5,8 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; import net.halbear.Terrain4J.EngineCore.Logic.InitData; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.SkyBox; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +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.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiRenderer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiTexture; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Lighting.LightRenderer; @@ -28,6 +30,8 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain. import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.SwapChainRender; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; import net.halbear.Terrain4J.EngineCore.Threads.RenderThread; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkCommandBufferSubmitInfo; import org.lwjgl.vulkan.VkExtent2D; @@ -179,6 +183,8 @@ public class VulkanRenderer implements Renderer { spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache); spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache); GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache); + VoxelWorldManager.Init(RendererContext); + // VoxelWorldManager.GenerateChunks(new Vector3i(0,0,0), new Vector3i(16,0,16)); } public GuiRenderer GetGUIRenderer(){return GuiRender;} @@ -196,6 +202,9 @@ public class VulkanRenderer implements Renderer { public void cleanup() { RendererContext.GetDevice().waitIdle(); Logger.debug("Waiting Vulkan Context"); + + VoxelWorldManager.Cleanup(RendererContext); + sceneRender.cleanup(RendererContext); if(ssaoRenderer != null)ssaoRenderer.cleanup(RendererContext); if(ssrRender != null)ssrRender.cleanup(RendererContext); @@ -239,7 +248,7 @@ public class VulkanRenderer implements Renderer { public static volatile boolean Debug = false; public static volatile DebugRenderMode debugMode = DebugRenderMode.Albedo; - + Vector3f CamPos = new Vector3f(); public void DeferredRender(EngineInstance engineInstance){ SwapChain swapChain = RendererContext.GetSwapChain(); WaitForFence(CurrentFrame); @@ -247,9 +256,8 @@ public class VulkanRenderer implements Renderer { var CommandPool = CommandPools[CurrentFrame]; var CommandBuffer = CommandBuffers[CurrentFrame]; - RecordingStart(CommandPool, CommandBuffer); - + VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer); sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame); boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows(); if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); } @@ -289,9 +297,8 @@ public class VulkanRenderer implements Renderer { resize(engineInstance); return; } - RecordingStart(CommandPool, CommandBuffer); - + VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer); sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame); PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour()); spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java index 77af47b..31345c3 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java @@ -29,6 +29,8 @@ 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.Vulkan.Computing.VoxelTerrainGeneration.VoxelChunkGenerator; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager; import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils; import net.halbear.Terrain4J.EngineCore.ServerNetworking.ServerSideNetworkUtils; import net.halbear.Terrain4J.EngineCore.Threads.RenderThread; @@ -36,13 +38,11 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPass import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialData; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelData; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Forward.ForwardSceneRender; -import org.joml.Matrix4f; -import org.joml.Vector2f; -import org.joml.Vector3f; -import org.joml.Vector3i; +import org.joml.*; import org.lwjgl.openal.AL11; import org.tinylog.Logger; +import java.lang.Math; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -51,7 +51,7 @@ import static org.lwjgl.glfw.GLFW.*; public class GameCore implements GameLogic { private static final float MOUSE_SENSITIVITY = 0.1f; - private static final float MOVEMENT_SPEED = 0.01f; + private static final float MOVEMENT_SPEED = 0.1f; public static boolean LoadingLevel = false; private Vector2f LastMousePos = new Vector2f(0,0); @@ -161,6 +161,9 @@ public class GameCore implements GameLogic { } boolean createOfflinePlayer = !PrimaryRuntime.IsServer && !ClientSideNetworkUtils.Connected; + MaterialData VoxelMat = new MaterialData("VoxelTerrain","resources/EngineResources/Texture/test_cube.png","","",new Vector4f(1,1,1,1), + 0,0,"",new Vector4f(),"",0,"",1,new Vector4f(),1.0f,0); + materials.add(VoxelMat); materials.addAll(MelonaMat); materials.addAll(CollisionVisualisationMat); materials.addAll(MelonaMaterial); @@ -283,11 +286,11 @@ public class GameCore implements GameLogic { permutation.GeneratePermutationArray(5783904701859L); for(int x = -1; x < 2; x++){ for(int y = -1; y < 2; y++){ - GenerateChunk(new Vector3i(x, 0, y), 16); + //GenerateChunk(new Vector3i(x, 0, y), 16); } } for(int i = 0; i < 20; i++){ - SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1)); + //SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1)); } Settings.textBuffer.set(ClientSideNetworkUtils.ServerIP); Settings.UsernameBuffer.set("Player"); @@ -651,10 +654,20 @@ public class GameCore implements GameLogic { FetchingMetrics = false; return imGuiIO.getWantCaptureKeyboard(); } - + Vector3f CamPos = new Vector3f(); @Override public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) { if(!PrimaryRuntime.IsServer && !RenderThread.Headless) { + CamPos.set(engineInstance.scene().GetCamera().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, 3, 5)); + VoxelWorldManager.UnloadFarChunks(ChunkPos, 10); + } else { + VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,10,24)); + VoxelWorldManager.UnloadFarChunks(ChunkPos, 48); + } + for (int i = 0; i < VisualisedCollisionActor3D.CollisionVisuals.size(); i++) { VisualisedCollisionActor3D.CollisionVisuals.get(i).Update(); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/ComputeVoxelTerrain.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/ComputeVoxelTerrain.java new file mode 100644 index 0000000..6ad847f --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/ComputeVoxelTerrain.java @@ -0,0 +1,330 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil.ComputePipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelsCache; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.joml.Matrix4f; +import org.joml.Vector3i; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.util.shaderc.Shaderc; +import org.lwjgl.vulkan.*; +import org.tinylog.Logger; + +import java.nio.ByteBuffer; +import java.nio.LongBuffer; + +import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.BufferBarrier; +import static org.lwjgl.system.MemoryUtil.memFree; +import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK10.VK_PIPELINE_BIND_POINT_COMPUTE; +import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_COMPUTE_BIT; +import static org.lwjgl.vulkan.VK10.vkCmdDispatch; +import static org.lwjgl.vulkan.VK10.vkCmdPushConstants; +import static org.lwjgl.vulkan.VK13.*; + +public class ComputeVoxelTerrain { + public static final int CHUNK_SIZE = 16; + public static final int LOCAL_SIZE = 4; + public static final int DISPATCH_SIZE = CHUNK_SIZE / LOCAL_SIZE; + + public static final int CHUNK_PUSH_CONSTANT_SIZE = Integer.BYTES * 4; + + private static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; + private static final int MAX_FACES = VOXEL_COUNT * 6; + private static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * 16; + private static final int MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * 4; + private static final int MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * 6; + + private static final int FLOATS_PER_VERTEX = 14; + private static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES; + private static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES; + private static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES; + + private final String DESCRIPTOR_ID_MESH; + private final String DESCRIPTOR_ID_RESET; + private final String DESCRIPTOR_ID_VOXEL; + + private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl"; + private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl"; + private static final String VOXEL_RESET_GLSL = "resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl"; + + private static final String MESH_GENERATION_SPV = MESH_GENERATION_GLSL + ".spv"; + private static final String VOXEL_GENERATION_SPV = VOXEL_GENERATION_GLSL + ".spv"; + private static final String VOXEL_RESET_SPV = VOXEL_RESET_GLSL + ".spv"; + + private final VulkanBuffer VoxelData; + private final VulkanBuffer VertexBuffer; + private final VulkanBuffer IndexBuffer; + private final VulkanBuffer DrawCommand; + private final VulkanBuffer Counters; + + private final DescriptorSetLayout voxelGenerationLayout; + private final DescriptorSetLayout resetLayout; + private final DescriptorSetLayout meshGenerationLayout; + + private final Pipeline voxelGeneration; + private final Pipeline voxelReset; + private final Pipeline meshGeneration; + + private final ByteBuffer graphicsPushConstants; + + private final int chunkX; + private final int chunkY; + private final int chunkZ; + + private boolean generated; + + public ComputeVoxelTerrain(VulkanContext VkCtx, int chunkX, int chunkY, int chunkZ) { + this.chunkX = chunkX; + this.chunkY = chunkY; + this.chunkZ = chunkZ; + this.generated = false; + DESCRIPTOR_ID_MESH = "DESC_ID_MESH_" + chunkX + "_" + chunkY + "_" + chunkZ; + DESCRIPTOR_ID_RESET = "DESC_ID_RESET_" + chunkX + "_" + chunkY + "_" + chunkZ; + DESCRIPTOR_ID_VOXEL = "DESC_ID_VOXEL_" + chunkX + "_" + chunkY + "_" + chunkZ; + long voxelBufferSize = (long) VOXEL_COUNT * Integer.BYTES; + long vertexBufferSize = (long) MAX_VERTICES * VERTEX_SIZE_BYTES; + long indexBufferSize = (long) MAX_INDICES * Integer.BYTES; + + VoxelData = new VulkanBuffer(VkCtx,voxelBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + VertexBuffer = new VulkanBuffer( VkCtx, vertexBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + IndexBuffer = new VulkanBuffer(VkCtx,indexBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + DrawCommand = new VulkanBuffer(VkCtx,DRAW_INDEXED_INDIRECT_COMMAND_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + Counters = new VulkanBuffer(VkCtx,COUNTER_BUFFER_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1, + VK_SHADER_STAGE_COMPUTE_BIT ) }); + resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1, + VK_SHADER_STAGE_COMPUTE_BIT ), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1, + VK_SHADER_STAGE_COMPUTE_BIT ) }); + meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0, + 1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1, + 1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,2, + 1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,3, + 1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4, + 1,VK_SHADER_STAGE_COMPUTE_BIT),}); + createDescriptorSets(VkCtx); + PushConstantsRange[] chunkPushConstants = new PushConstantsRange[]{ + new PushConstantsRange( + VK_SHADER_STAGE_COMPUTE_BIT, + 0, + CHUNK_PUSH_CONSTANT_SIZE + ) + }; + ShaderModule resetShader = createComputeShader(VkCtx, VOXEL_RESET_GLSL, VOXEL_RESET_SPV); + ShaderModule voxelShader = createComputeShader(VkCtx, VOXEL_GENERATION_GLSL, VOXEL_GENERATION_SPV); + ShaderModule meshShader = createComputeShader(VkCtx, MESH_GENERATION_GLSL, MESH_GENERATION_SPV); + voxelReset = new ComputePipeline( VkCtx, resetShader,new DescriptorSetLayout[]{resetLayout}, + new PushConstantsRange[0]); + voxelGeneration = new ComputePipeline( VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout}, + chunkPushConstants ); + meshGeneration = new ComputePipeline(VkCtx, meshShader,new DescriptorSetLayout[]{meshGenerationLayout}, + chunkPushConstants ); + resetShader.CleanUp(VkCtx); + voxelShader.CleanUp(VkCtx); + meshShader.CleanUp(VkCtx); + graphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc(VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE); + } + + private static ShaderModule createComputeShader(VulkanContext VkCtx, String glslPath, String spvPath) { + if (EngineConfig.getInstance().RecompileShaders()) { + ShaderCompiler.CompileGLSLShaderOnChange(glslPath, Shaderc.shaderc_glsl_compute_shader); + } + + return new ShaderModule(VkCtx, VK_SHADER_STAGE_COMPUTE_BIT, spvPath, null); + } + + private void createDescriptorSets(VulkanContext VkCtx) { + DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator(); + Device device = VkCtx.GetDevice(); + + DescriptorSet resetSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_RESET, resetLayout); + resetSet.SetBuffer(device, DrawCommand, DrawCommand.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + resetSet.SetBuffer(device, Counters, Counters.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + + DescriptorSet voxelSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_VOXEL, voxelGenerationLayout); + voxelSet.SetBuffer(device, VoxelData, VoxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + + DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_MESH, meshGenerationLayout); + meshSet.SetBuffer(device, VoxelData, VoxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, VertexBuffer, VertexBuffer.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, IndexBuffer, IndexBuffer.GetRequestedSize(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, DrawCommand, DrawCommand.GetRequestedSize(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, Counters, Counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + } + + public void RecordGeneration(VulkanContext VkCtx, CommandBuffer commandBuffer) { + if (generated) { + return; + } + + try (MemoryStack MemStack = MemoryStack.stackPush()) { + VkCommandBuffer CommandBuffer = commandBuffer.GetVulkanCommandBuffer(); + DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator(); + + ByteBuffer chunkPushBuffer = MemStack.malloc(CHUNK_PUSH_CONSTANT_SIZE); + chunkPushBuffer.putInt(0, chunkX); + chunkPushBuffer.putInt(4, chunkY); + chunkPushBuffer.putInt(8, chunkZ); + chunkPushBuffer.putInt(12, 0); + + LongBuffer resetDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_RESET).GetVkDescriptorSet()); + + LongBuffer voxelDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_VOXEL).GetVkDescriptorSet()); + + LongBuffer meshDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_MESH).GetVkDescriptorSet()); + + vkCmdBindPipeline(CommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,voxelReset.GetVulkanPipeline()); + + vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelReset.GetVulkanPipelineLayout(),0,resetDescriptorSet,null); + + vkCmdDispatch(CommandBuffer, 1, 1, 1); + + VulkanUtils.BufferBarriers(MemStack, CommandBuffer, + new long[]{DrawCommand.GetBuffer(),Counters.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_ACCESS_2_SHADER_WRITE_BIT); + + vkCmdBindPipeline(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelGeneration.GetVulkanPipeline()); + + vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelGeneration.GetVulkanPipelineLayout(),0, voxelDescriptorSet,null); + + vkCmdPushConstants(CommandBuffer,voxelGeneration.GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0,chunkPushBuffer); + + vkCmdDispatch(CommandBuffer, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE); + + BufferBarrier(MemStack, CommandBuffer, 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); + + vkCmdBindPipeline(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,meshGeneration.GetVulkanPipeline()); + + vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,meshGeneration.GetVulkanPipelineLayout(),0, meshDescriptorSet,null); + + vkCmdPushConstants(CommandBuffer, meshGeneration.GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0,chunkPushBuffer); + + vkCmdDispatch(CommandBuffer, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE); + + VulkanUtils.BufferBarriers(MemStack, CommandBuffer, + new long[]{VertexBuffer.GetBuffer(), + IndexBuffer.GetBuffer(), + DrawCommand.GetBuffer()}, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT, + VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_2_INDEX_READ_BIT | VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT); + + generated = true; + } + } + + public void RecordRender(VkCommandBuffer CommandBuffer, Pipeline graphicsPipeline,Matrix4f modelMatrix, int materialIndex) { + try (MemoryStack stack = MemoryStack.stackPush()) { + modelMatrix.get(0, graphicsPushConstants); + graphicsPushConstants.putInt(VulkanUtils.MATRIX4X4_SIZE, materialIndex); + // Logger.debug("Rendering Chunk {}:{}:{}",chunkX,chunkY,chunkZ); + vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT,0, graphicsPushConstants.slice(0, VulkanUtils.MATRIX4X4_SIZE)); + + vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_FRAGMENT_BIT,VulkanUtils.MATRIX4X4_SIZE, graphicsPushConstants.slice(VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.INT_SIZE)); + + LongBuffer vertexBuffers = stack.longs(VertexBuffer.GetBuffer()); + LongBuffer offsets = stack.longs(0L); + + vkCmdBindVertexBuffers(CommandBuffer, 0, vertexBuffers, offsets); + vkCmdBindIndexBuffer(CommandBuffer, IndexBuffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + + //vkCmdDrawIndexed(CommandBuffer,MAX_INDICES,1,0,0,0); + vkCmdDrawIndexedIndirect(CommandBuffer,DrawCommand.GetBuffer(),0,1,DRAW_INDEXED_INDIRECT_COMMAND_SIZE); + } + } + + public VulkanBuffer GetVoxelDataBuffer() { + return VoxelData; + } + + public VulkanBuffer GetVertexBuffer() { + return VertexBuffer; + } + + public VulkanBuffer GetIndexBuffer() { + return IndexBuffer; + } + + public VulkanBuffer GetDrawCommandBuffer() { + return DrawCommand; + } + + public VulkanBuffer GetCountersBuffer() { + return Counters; + } + + public boolean IsGenerated() { + return generated; + } + + public void MarkDirty() { + generated = false; + } + + public Vector3i GetPosition(){ + return new Vector3i(chunkX,chunkY,chunkZ); + } + + public void cleanup(VulkanContext VkCtx) { + voxelGeneration.CleanUp(VkCtx); + voxelReset.CleanUp(VkCtx); + meshGeneration.CleanUp(VkCtx); + + voxelGenerationLayout.CleanUp(VkCtx); + resetLayout.CleanUp(VkCtx); + meshGenerationLayout.CleanUp(VkCtx); + + VoxelData.cleanup(VkCtx); + VertexBuffer.cleanup(VkCtx); + IndexBuffer.cleanup(VkCtx); + DrawCommand.cleanup(VkCtx); + Counters.cleanup(VkCtx); + + org.lwjgl.system.MemoryUtil.memFree(graphicsPushConstants); + } + + public void recordComputeCommandBuffer(VkCommandBuffer cmd, long computePipeline, long pipelineLayout, + long descriptorSet, int chunkX, int chunkY, int chunkZ) { + try (MemoryStack MemStack = MemoryStack.stackPush()) { + ByteBuffer pushConstants = MemStack.malloc(CHUNK_PUSH_CONSTANT_SIZE); + pushConstants.putInt(0, chunkX); + pushConstants.putInt(4, chunkY); + pushConstants.putInt(8, chunkZ); + pushConstants.putInt(12, 0); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline); + vkCmdBindDescriptorSets(cmd,VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, + 0,MemStack.longs(descriptorSet),null); + + vkCmdPushConstants(cmd,pipelineLayout,VK_SHADER_STAGE_COMPUTE_BIT,0,pushConstants); + + vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE); + } + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/RenderChunk.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/RenderChunk.java new file mode 100644 index 0000000..9ca26fd --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/RenderChunk.java @@ -0,0 +1,6 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import org.joml.Vector3i; + +public record RenderChunk(Vector3i position, int slot,long vertexOffsetBytes, long indexOffsetBytes,int maxIndexCount,long indirectCommandOffsetBytes) { +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java new file mode 100644 index 0000000..6129788 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java @@ -0,0 +1,182 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil.ComputePipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; +import org.lwjgl.util.shaderc.Shaderc; + +import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; +import static org.lwjgl.vulkan.VK13.*; + +public class SharedVoxelTerrainResources { + public static final int CHUNK_SIZE = 16; + public static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; + + public static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES; + public static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES; + + + public static final int TERRAIN_GENERATION_PUSH_CONSTANT_SIZE = Integer.BYTES * 8; + /*Push constants: + int chunkX + int chunkY + int chunkZ + int slot + uint vertexFloatOffset + uint indexOffset + uint indirectCommandOffset + uint padding */ + private static final String DESC_ID_VOXEL_GENERATION = "VOXEL_SHARED_DESC_GENERATION"; + private static final String DESC_ID_RESET = "VOXEL_SHARED_DESC_RESET"; + private static final String DESC_ID_MESH = "VOXEL_SHARED_DESC_MESH"; + + private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl"; + private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl"; + private static final String VOXEL_RESET_GLSL = "resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl"; + + private static final String MESH_GENERATION_SPV = MESH_GENERATION_GLSL + ".spv"; + private static final String VOXEL_GENERATION_SPV = VOXEL_GENERATION_GLSL + ".spv"; + private static final String VOXEL_RESET_SPV = VOXEL_RESET_GLSL + ".spv"; + + private final VoxelMeshPool meshPool; + + private final VulkanBuffer voxelData; + private final VulkanBuffer counters; + + private final DescriptorSetLayout voxelGenerationLayout; + private final DescriptorSetLayout resetLayout; + private final DescriptorSetLayout meshGenerationLayout; + + private final Pipeline voxelGenerationPipeline; + private final Pipeline resetPipeline; + private final Pipeline meshGenerationPipeline; + + public SharedVoxelTerrainResources(VulkanContext VkCtx, int maxResidentChunks) { + meshPool = new VoxelMeshPool(VkCtx, maxResidentChunks); + + voxelData = new VulkanBuffer(VkCtx, (long) VOXEL_COUNT * Integer.BYTES, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + + counters = new VulkanBuffer( VkCtx,COUNTER_BUFFER_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); + + voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT) + }); + + resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,VK_SHADER_STAGE_COMPUTE_BIT) + }); + + meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,2,1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,3,1,VK_SHADER_STAGE_COMPUTE_BIT), + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4,1,VK_SHADER_STAGE_COMPUTE_BIT) + }); + + createDescriptorSets(VkCtx); + + PushConstantsRange[] generationPushConstants = new PushConstantsRange[]{ + new PushConstantsRange(VK_SHADER_STAGE_COMPUTE_BIT,0, TERRAIN_GENERATION_PUSH_CONSTANT_SIZE) + }; + + ShaderModule resetShader = createComputeShader(VkCtx, VOXEL_RESET_GLSL, VOXEL_RESET_SPV); + ShaderModule voxelShader = createComputeShader(VkCtx, VOXEL_GENERATION_GLSL, VOXEL_GENERATION_SPV); + ShaderModule meshShader = createComputeShader(VkCtx, MESH_GENERATION_GLSL, MESH_GENERATION_SPV); + + resetPipeline = new ComputePipeline(VkCtx,resetShader,new DescriptorSetLayout[]{resetLayout},generationPushConstants); + + voxelGenerationPipeline = new ComputePipeline(VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout},generationPushConstants); + + meshGenerationPipeline = new ComputePipeline( VkCtx,meshShader, new DescriptorSetLayout[]{meshGenerationLayout},generationPushConstants ); + + resetShader.CleanUp(VkCtx); + voxelShader.CleanUp(VkCtx); + meshShader.CleanUp(VkCtx); + } + + private static ShaderModule createComputeShader(VulkanContext VkCtx, String glslPath, String spvPath) { + if (EngineConfig.getInstance().RecompileShaders()) { + ShaderCompiler.CompileGLSLShaderOnChange(glslPath, Shaderc.shaderc_glsl_compute_shader); + } + + return new ShaderModule(VkCtx, VK_SHADER_STAGE_COMPUTE_BIT, spvPath, null); + } + + private void createDescriptorSets(VulkanContext VkCtx) { + DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator(); + Device device = VkCtx.GetDevice(); + + DescriptorSet resetSet = allocator.AddDescriptorSet(device, DESC_ID_RESET, resetLayout); + resetSet.SetBuffer(device, meshPool.indirectPool(), meshPool.indirectPool().GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + resetSet.SetBuffer(device, counters, counters.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + + DescriptorSet voxelSet = allocator.AddDescriptorSet(device, DESC_ID_VOXEL_GENERATION, voxelGenerationLayout); + voxelSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + + DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESC_ID_MESH, meshGenerationLayout); + meshSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, meshPool.vertexPool(), meshPool.vertexPool().GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, meshPool.indexPool(), meshPool.indexPool().GetRequestedSize(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, meshPool.indirectPool(), meshPool.indirectPool().GetRequestedSize(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + meshSet.SetBuffer(device, counters, counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + } + + public VoxelMeshPool meshPool() { + return meshPool; + } + + public VulkanBuffer voxelData() { + return voxelData; + } + + public VulkanBuffer counters() { + return counters; + } + + public Pipeline voxelGenerationPipeline() { + return voxelGenerationPipeline; + } + + public Pipeline resetPipeline() { + return resetPipeline; + } + + public Pipeline meshGenerationPipeline() { + return meshGenerationPipeline; + } + + public String voxelGenerationDescriptorId() { + return DESC_ID_VOXEL_GENERATION; + } + + public String resetDescriptorId() { + return DESC_ID_RESET; + } + + public String meshDescriptorId() { + return DESC_ID_MESH; + } + + public void cleanup(VulkanContext VkCtx) { + resetPipeline.CleanUp(VkCtx); + voxelGenerationPipeline.CleanUp(VkCtx); + meshGenerationPipeline.CleanUp(VkCtx); + + resetLayout.CleanUp(VkCtx); + voxelGenerationLayout.CleanUp(VkCtx); + meshGenerationLayout.CleanUp(VkCtx); + + voxelData.cleanup(VkCtx); + counters.cleanup(VkCtx); + meshPool.cleanup(VkCtx); + } +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java new file mode 100644 index 0000000..0dcfd58 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java @@ -0,0 +1,121 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.DescriptorAllocator; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkCommandBuffer; + +import java.nio.ByteBuffer; +import java.nio.LongBuffer; + +import static org.lwjgl.vulkan.VK13.*; + +public class VoxelChunkGenerator { + public static final int CHUNK_SIZE = 16; + public static final int LOCAL_SIZE = 4; + public static final int DISPATCH_SIZE = CHUNK_SIZE / LOCAL_SIZE; + + private final SharedVoxelTerrainResources resources; + + public VoxelChunkGenerator(SharedVoxelTerrainResources resources) { + this.resources = resources; + } + + public void recordGenerateChunk(VulkanContext VkCtx,CommandBuffer commandBuffer, RenderChunk chunk) { + try (MemoryStack stack = MemoryStack.stackPush()) { + VkCommandBuffer cmd = commandBuffer.GetVulkanCommandBuffer(); + DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator(); + + ByteBuffer pushConstants = stack.malloc(SharedVoxelTerrainResources.TERRAIN_GENERATION_PUSH_CONSTANT_SIZE); + + int vertexFloatOffset = (int) (chunk.vertexOffsetBytes() / Float.BYTES); + int indexOffset = (int) (chunk.indexOffsetBytes() / Integer.BYTES); + int indirectCommandIndex = (int) (chunk.indirectCommandOffsetBytes() / VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE); + + pushConstants.putInt(0, chunk.position().x); + pushConstants.putInt(4, chunk.position().y); + pushConstants.putInt(8, chunk.position().z); + pushConstants.putInt(12, chunk.slot()); + pushConstants.putInt(16, vertexFloatOffset); + pushConstants.putInt(20, indexOffset); + 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() + ); + + 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[]{ + resources.meshPool().indirectPoolHandle(), + resources.counters().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_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 + ); + + vkCmdBindPipeline(cmd,VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipeline() ); + + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipelineLayout(),0, meshDescriptorSet,null ); + + vkCmdPushConstants( cmd, resources.meshGenerationPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants ); + + vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE); + + VulkanUtils.BufferBarriers(stack, cmd, + new long[]{ + resources.voxelData().GetBuffer(), + resources.counters().GetBuffer(), + resources.meshPool().vertexPoolHandle(), + resources.meshPool().indexPoolHandle(), + resources.meshPool().indirectPoolHandle() + }, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | + VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT, + VK_ACCESS_2_SHADER_WRITE_BIT, + VK_ACCESS_2_SHADER_READ_BIT | + VK_ACCESS_2_SHADER_WRITE_BIT | + VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_2_INDEX_READ_BIT | + VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT + ); + } + } +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkVisibility.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkVisibility.java new file mode 100644 index 0000000..2a75bcb --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkVisibility.java @@ -0,0 +1,7 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +public enum VoxelChunkVisibility { + EMPTY_AIR, + FULLY_SOLID_UNDERGROUND, + SURFACE +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelMeshPool.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelMeshPool.java new file mode 100644 index 0000000..fb5d577 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelMeshPool.java @@ -0,0 +1,126 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; +import org.joml.Vector3i; + +import java.util.ArrayDeque; +import java.util.Queue; + +import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; +import static org.lwjgl.vulkan.VK13.*; + +public class VoxelMeshPool{ + public static final int CHUNK_SIZE = 16; + + public static final int FLOATS_PER_VERTEX = 14; + public static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES; + + public static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * 12; + public static final int MAX_VERTICES_PER_CHUNK = MAX_VISIBLE_FACES_PER_CHUNK * 4; + public static final int MAX_INDICES_PER_CHUNK = MAX_VISIBLE_FACES_PER_CHUNK * 6; + + public static final int INDEX_SIZE_BYTES = Integer.BYTES; + public static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES; + + private final int maxChunks; + + private final long vertexSlotSizeBytes; + private final long indexSlotSizeBytes; + private final long indirectSlotSizeBytes; + + private final VulkanBuffer vertexPool; + private final VulkanBuffer indexPool; + private final VulkanBuffer indirectPool; + + private final Queue freeSlots = new ArrayDeque<>(); + + public VoxelMeshPool(VulkanContext VkCtx, int maxChunks) { + this.maxChunks = maxChunks; + + this.vertexSlotSizeBytes = (long) MAX_VERTICES_PER_CHUNK * VERTEX_SIZE_BYTES; + this.indexSlotSizeBytes = (long) MAX_INDICES_PER_CHUNK * INDEX_SIZE_BYTES; + this.indirectSlotSizeBytes = DRAW_INDEXED_INDIRECT_COMMAND_SIZE; + + long vertexPoolSize = vertexSlotSizeBytes * maxChunks; + long indexPoolSize = indexSlotSizeBytes * maxChunks; + long indirectPoolSize = indirectSlotSizeBytes * maxChunks; + + vertexPool = new VulkanBuffer(VkCtx,vertexPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0); + + indexPool = new VulkanBuffer(VkCtx,indexPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0); + + indirectPool = new VulkanBuffer(VkCtx,indirectPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0); + + for (int i = 0; i < maxChunks; i++) { + freeSlots.add(i); + } + } + + public RenderChunk allocate(Vector3i position) { + Integer slot = freeSlots.poll(); + + if (slot == null) { + return null; + } + + return new RenderChunk(new Vector3i(position),slot, vertexOffsetBytes(slot),indexOffsetBytes(slot),MAX_INDICES_PER_CHUNK,indirectCommandOffsetBytes(slot)); + } + + public void free(RenderChunk chunk) { + freeSlots.add(chunk.slot()); + } + + public long vertexOffsetBytes(int slot) { + return vertexSlotSizeBytes * slot; + } + + public long indexOffsetBytes(int slot) { + return indexSlotSizeBytes * slot; + } + + public long indirectCommandOffsetBytes(int slot) { + return indirectSlotSizeBytes * slot; + } + + public VulkanBuffer vertexPool() { + return vertexPool; + } + + public VulkanBuffer indexPool() { + return indexPool; + } + + public VulkanBuffer indirectPool() { + return indirectPool; + } + + public long vertexPoolHandle() { + return vertexPool.GetBuffer(); + } + + public long indexPoolHandle() { + return indexPool.GetBuffer(); + } + + public long indirectPoolHandle() { + return indirectPool.GetBuffer(); + } + + public int maxChunks() { + return maxChunks; + } + + public int freeSlotCount() { + return freeSlots.size(); + } + + public void cleanup(VulkanContext VkCtx) { + vertexPool.cleanup(VkCtx); + indexPool.cleanup(VkCtx); + indirectPool.cleanup(VkCtx); + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelTerrainHeightSampler.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelTerrainHeightSampler.java new file mode 100644 index 0000000..9210387 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelTerrainHeightSampler.java @@ -0,0 +1,113 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +public final class VoxelTerrainHeightSampler { + private VoxelTerrainHeightSampler() { + } + + private static double fract(double value) { + return value - Math.floor(value); + } + + private static double mix(double a, double b, double t) { + return a * (1.0 - t) + b * t; + } + + private static double rand(double x, double z) { + return fract(Math.sin(x * 12.9898 + z * 78.233) * 43758.5453123); + } + + private static double valueNoise(double x, double z) { + double ix = Math.floor(x); + double iz = Math.floor(z); + + double fx = fract(x); + double fz = fract(z); + + double a = rand(ix, iz); + double b = rand(ix + 1.0, iz); + double c = rand(ix, iz + 1.0); + double d = rand(ix + 1.0, iz + 1.0); + + double ux = fx * fx * (3.0 - 2.0 * fx); + double uz = fz * fz * (3.0 - 2.0 * fz); + + return mix(mix(a, b, ux), mix(c, d, ux), uz); + } + + public static double terrainHeight(double worldX, double worldZ) { + return valueNoise(worldX * 0.005, worldZ * 0.005) * 100.0 + + valueNoise(worldX * 0.01, worldZ * 0.01) * 10.0 + + valueNoise(worldX * 0.1, worldZ * 0.1) * 5.0 + + valueNoise(worldX, worldZ) * 0.5; + } + + public static double minHeightForChunkXZ(int chunkX, int chunkZ, int chunkSize) { + double min = Double.POSITIVE_INFINITY; + + int worldMinX = chunkX * chunkSize; + int worldMinZ = chunkZ * chunkSize; + int worldMaxX = worldMinX + chunkSize - 1; + int worldMaxZ = worldMinZ + chunkSize - 1; + + int samplesPerAxis = 5; + + for (int sx = 0; sx < samplesPerAxis; sx++) { + for (int sz = 0; sz < samplesPerAxis; sz++) { + double tx = sx / (double) (samplesPerAxis - 1); + double tz = sz / (double) (samplesPerAxis - 1); + + double x = mix(worldMinX, worldMaxX, tx); + double z = mix(worldMinZ, worldMaxZ, tz); + + min = Math.min(min, terrainHeight(x, z)); + } + } + + return min; + } + + public static double maxHeightForChunkXZ(int chunkX, int chunkZ, int chunkSize) { + double max = Double.NEGATIVE_INFINITY; + + int worldMinX = chunkX * chunkSize; + int worldMinZ = chunkZ * chunkSize; + int worldMaxX = worldMinX + chunkSize - 1; + int worldMaxZ = worldMinZ + chunkSize - 1; + + int samplesPerAxis = 5; + + for (int sx = 0; sx < samplesPerAxis; sx++) { + for (int sz = 0; sz < samplesPerAxis; sz++) { + double tx = sx / (double) (samplesPerAxis - 1); + double tz = sz / (double) (samplesPerAxis - 1); + + double x = mix(worldMinX, worldMaxX, tx); + double z = mix(worldMinZ, worldMaxZ, tz); + + max = Math.max(max, terrainHeight(x, z)); + } + } + + return max; + } + + public static VoxelChunkVisibility classifyChunk(int chunkX, int chunkY, int chunkZ, int chunkSize) { + int chunkMinY = chunkY * chunkSize; + int chunkMaxY = chunkMinY + chunkSize - 1; + + double minHeight = minHeightForChunkXZ(chunkX, chunkZ, chunkSize); + double maxHeight = maxHeightForChunkXZ(chunkX, chunkZ, chunkSize); + + double safetyPadding = 32.0; + + if (chunkMinY > maxHeight + safetyPadding) { + return VoxelChunkVisibility.EMPTY_AIR; + } + + if (chunkMaxY < minHeight - safetyPadding) { + return VoxelChunkVisibility.FULLY_SOLID_UNDERGROUND; + } + + return VoxelChunkVisibility.SURFACE; + } +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java new file mode 100644 index 0000000..29244e6 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java @@ -0,0 +1,274 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; +import org.joml.Matrix4f; +import org.joml.Vector3i; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkCommandBuffer; +import org.tinylog.Logger; + +import java.nio.ByteBuffer; +import java.nio.LongBuffer; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +import static org.lwjgl.vulkan.VK13.*; + +public class VoxelWorldManager { + private static final int MAX_RESIDENT_CHUNKS = 512 * 24; + private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 32; + + private static final ConcurrentLinkedQueue RequestedChunks = new ConcurrentLinkedQueue<>(); + private static final ConcurrentHashMap RenderChunks = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap KnownChunks = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap CulledChunks = new ConcurrentHashMap<>(); + + + private static SharedVoxelTerrainResources Resources; + private static VoxelChunkGenerator Generator; + + private static ByteBuffer GraphicsPushConstants; + + public static void Init(VulkanContext VkCtx) { + if (Resources != null) { + return; + } + + Resources = new SharedVoxelTerrainResources(VkCtx, MAX_RESIDENT_CHUNKS); + Generator = new VoxelChunkGenerator(Resources); + + GraphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc( + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE + + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE + ); + } + + public static void GenerateChunk(Vector3i Position) { + Vector3i key = new Vector3i(Position); + + if (KnownChunks.containsKey(key)) { + return; + } + + RequestedChunks.add(key); + KnownChunks.put(key, true); + } + + public static int GenerationOffset = 0; + public static Vector3i LastPosition = new Vector3i(0, 0, 0); + + static int IterationX = 0; + static Vector3i ChunkPos = new Vector3i(0, 0, 0); + static Vector3i ChunkPos2 = new Vector3i(0, 0, 0); + + public static void GenerateChunks(Vector3i Position, Vector3i Radius) { + int ChunkX = Position.x; + int ChunkY = Position.y; + int ChunkY2 = Position.y; + int ChunkZ = Position.z; + for (int Ry = 0; Ry <= Radius.y; Ry++) + { + for (int Rx = -IterationX; Rx <= IterationX; Rx++) + { + for (int Rz = -IterationX; Rz <= IterationX; Rz++) + { + ChunkX = Position.x + Rx; + ChunkY = Position.y + Ry; + ChunkY2 = Position.y - Ry; + ChunkZ = Position.z + Rz; + if (Rx == -IterationX || Rz == -IterationX || Rx == IterationX || Rz == IterationX) + { + GenerateChunk(ChunkPos.set(ChunkX, ChunkY, ChunkZ)); + GenerateChunk(ChunkPos2.set(ChunkX, ChunkY2, ChunkZ)); + } + } + } + } + IterationX++; + if (IterationX > Radius.x || Position.x != LastPosition.x || Position.y != LastPosition.y || Position.z != LastPosition.z) + { + IterationX = 0; + } + LastPosition.set(Position); + } + + public static void RecordGeneration(VulkanContext VkCtx, CommandBuffer commandBuffer) { + if (Resources == null) { + Init(VkCtx); + } + + int generatedThisFrame = 0; + + while (!RequestedChunks.isEmpty() && generatedThisFrame < MAX_CHUNK_GENERATIONS_PER_FRAME) { + Vector3i position = RequestedChunks.poll(); + + if (position == null) { + break; + } + +// VoxelChunkVisibility visibility = VoxelTerrainHeightSampler.classifyChunk( +// position.x, +// position.y, +// position.z, +// VoxelChunkGenerator.CHUNK_SIZE +// ); +// +// if (visibility != VoxelChunkVisibility.SURFACE) { +// CulledChunks.put(new Vector3i(position), visibility); +// continue; +// } + + RenderChunk renderChunk = Resources.meshPool().allocate(position); + + if (renderChunk == null) { + Logger.warn("Voxel mesh pool full. Could not allocate chunk {}", position); + RequestedChunks.add(position); + break; + } + + Generator.recordGenerateChunk(VkCtx, commandBuffer, renderChunk); + RenderChunks.put(new Vector3i(position), renderChunk); + + generatedThisFrame++; + } + } + + public static void RecordRender(VkCommandBuffer CommandBuffer,Pipeline graphicsPipeline, MaterialsCache materialsCache) { + if (Resources == null) { + return; + } + + int terrainMaterialIndex = materialsCache.GetPosition("VoxelTerrain"); + + if (terrainMaterialIndex < 0) { + terrainMaterialIndex = 0; + } + + try (MemoryStack stack = MemoryStack.stackPush()) { + Matrix4f identity = new Matrix4f().identity(); + + identity.get(0, GraphicsPushConstants); + GraphicsPushConstants.putInt( + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE, + terrainMaterialIndex + ); + + vkCmdPushConstants(CommandBuffer, graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT, + 0,GraphicsPushConstants.slice( + 0, + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE)); + + vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT, + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE, + GraphicsPushConstants.slice( + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE, + net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE ) ); + + LongBuffer vertexBuffers = stack.longs(Resources.meshPool().vertexPoolHandle()); + LongBuffer offsets = stack.longs(0L); + + vkCmdBindVertexBuffers(CommandBuffer, 0, vertexBuffers, offsets); + vkCmdBindIndexBuffer(CommandBuffer, Resources.meshPool().indexPoolHandle(), 0, VK_INDEX_TYPE_UINT32); + + RenderChunks.forEach((position, chunk) -> vkCmdDrawIndexedIndirect(CommandBuffer,Resources.meshPool().indirectPoolHandle(), + chunk.indirectCommandOffsetBytes(), 1,VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE)); + } + } + + public static void UnloadFarChunks(Vector3i centerChunk, int unloadRadius) { + int maxDistSq = unloadRadius * unloadRadius; + + RenderChunks.entrySet().removeIf(entry -> { + Vector3i pos = entry.getKey(); + + 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) { + RenderChunk chunk = entry.getValue(); + + Resources.meshPool().free(chunk); + KnownChunks.remove(pos); + + return true; + } + + return false; + }); + + CulledChunks.entrySet().removeIf(entry -> { + Vector3i pos = entry.getKey(); + + 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) { + KnownChunks.remove(pos); + return true; + } + + return false; + }); + + RequestedChunks.removeIf(pos -> { + 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) { + KnownChunks.remove(pos); + return true; + } + + return false; + }); + } + + public static int GetRenderableChunkCount() { + return RenderChunks.size(); + } + + public static int GetCulledChunkCount() { + return CulledChunks.size(); + } + + public static int GetRequestedChunkCount() { + return RequestedChunks.size(); + } + + public static int GetFreeMeshSlots() { + if (Resources == null) { + return 0; + } + + return Resources.meshPool().freeSlotCount(); + } + + + public static void Cleanup(VulkanContext VkCtx) { + if (Resources != null) { + Resources.cleanup(VkCtx); + Resources = null; + } + + if (GraphicsPushConstants != null) { + org.lwjgl.system.MemoryUtil.memFree(GraphicsPushConstants); + GraphicsPushConstants = null; + } + + RequestedChunks.clear(); + RenderChunks.clear(); + KnownChunks.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VulkanUtil/ComputePipeline.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VulkanUtil/ComputePipeline.java new file mode 100644 index 0000000..c116cfa --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VulkanUtil/ComputePipeline.java @@ -0,0 +1,94 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil; + +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.DescriptorSetLayout; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.ShaderModule; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.nio.ByteBuffer; +import java.nio.LongBuffer; + +import static org.lwjgl.vulkan.VK10.*; + +public class ComputePipeline implements Pipeline { + + private final long VulkanPipeline; + private final long VulkanPipelineLayout; + + public ComputePipeline(VulkanContext VkCtx,ShaderModule shaderModule, DescriptorSetLayout[] descriptorSetLayouts,PushConstantsRange[] pushConstantsRanges) { + Device device = VkCtx.GetDevice(); + + try (MemoryStack stack = MemoryStack.stackPush()) { + LongBuffer pPipelineLayout = stack.mallocLong(1); + LongBuffer pPipeline = stack.mallocLong(1); + int layoutCount = descriptorSetLayouts != null ? descriptorSetLayouts.length : 0; + LongBuffer setLayouts = stack.mallocLong(layoutCount); + for (int i = 0; i < layoutCount; i++) { + setLayouts.put(i, descriptorSetLayouts[i].GetVkDescriptorLayout()); + } + + VkPushConstantRange.Buffer pushRanges = null; + int pushRangeCount = pushConstantsRanges != null ? pushConstantsRanges.length : 0; + if (pushRangeCount > 0) { + pushRanges = VkPushConstantRange.calloc(pushRangeCount, stack); + + for (int i = 0; i < pushRangeCount; i++) { + PushConstantsRange range = pushConstantsRanges[i]; + + pushRanges.get(i) + .stageFlags(range.Stage()) + .offset(range.Offset()) + .size(range.Size()); + } + } + VkPipelineLayoutCreateInfo layoutInfo = VkPipelineLayoutCreateInfo.calloc(stack) + .sType$Default() + .pSetLayouts(setLayouts) + .pPushConstantRanges(pushRanges); + + VulkanUtils.vkCheck( + vkCreatePipelineLayout(device.FetchVulkanDevice(), layoutInfo, null, pPipelineLayout), + "Unable to create compute pipeline layout" + ); + VulkanPipelineLayout = pPipelineLayout.get(0); + ByteBuffer main = stack.UTF8("main"); + VkPipelineShaderStageCreateInfo shaderStage = VkPipelineShaderStageCreateInfo.calloc(stack) + .sType$Default() + .stage(VK_SHADER_STAGE_COMPUTE_BIT) + .module(shaderModule.GetHandle()) + .pName(main); + + VkComputePipelineCreateInfo.Buffer pipelineInfo = VkComputePipelineCreateInfo.calloc(1, stack) + .sType$Default() + .stage(shaderStage) + .layout(VulkanPipelineLayout); + + VulkanUtils.vkCheck(vkCreateComputePipelines(device.FetchVulkanDevice(),VkCtx.GetVkPipelineCache().GetVkPipelineCache(), + pipelineInfo,null,pPipeline),"Unable to create compute pipeline" ); + + VulkanPipeline = pPipeline.get(0); + } + } + + @Override + public long GetVulkanPipeline() { + return VulkanPipeline; + } + + @Override + public long GetVulkanPipelineLayout() { + return VulkanPipelineLayout; + } + + @Override + public void CleanUp(VulkanContext VkCtx) { + VkDevice device = VkCtx.GetDevice().FetchVulkanDevice(); + vkDestroyPipeline(device, VulkanPipeline, null); + vkDestroyPipelineLayout(device, VulkanPipelineLayout, null); + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java index 54f10b7..f1a879c 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java @@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement; import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer; import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils; @@ -379,6 +380,8 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false); + VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache); + Matrix4f skyboxViewMatrix = new Matrix4f().identity(); skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix()); skyboxViewMatrix.m30(0.0f); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java index 3f92486..1ec818c 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java @@ -7,6 +7,7 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement; import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.DeferredRendering.DeferredSceneRender; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer; @@ -363,6 +364,7 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering .put(3,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet()); vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipelineLayout() : VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null); RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false); + VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache); Matrix4f skyboxViewMatrix = new Matrix4f().identity(); skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix()); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Shadows/ShadowRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Shadows/ShadowRenderer.java index 3237d80..7d90759 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Shadows/ShadowRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Shadows/ShadowRenderer.java @@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D; import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene; import net.halbear.Terrain4J.EngineCore.Main.Scene.SceneLightingManager; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ITexture; @@ -393,7 +394,7 @@ public class ShadowRenderer { vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0); } } - + VoxelWorldManager.RecordRender(cmdHandle,pipeline,materialsCache); vkCmdEndRendering(cmdHandle); } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java index 41e990f..70d1e22 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java @@ -47,6 +47,7 @@ public class DescriptorSet { .sType$Default() .dstSet(VkDescriptorSet) .dstBinding(Binding) + .dstArrayElement(0) .descriptorType(Type) .descriptorCount(1) .pBufferInfo(BufferInfo); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java index 3ba0d8f..6d8b588 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java @@ -206,6 +206,50 @@ public class VulkanUtils { } return result; } + + + public static void BufferBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long BufferHandle, + long SrcStage,long DstStage,long SrcAccess,long DstAccess){ + var BufferBarrier = VkBufferMemoryBarrier2.calloc(1, MemStack) + .sType$Default() + .srcStageMask(SrcStage) + .dstStageMask(DstStage) + .srcAccessMask(SrcAccess) + .dstAccessMask(DstAccess) + .srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .buffer(BufferHandle) + .offset(0) + .size(VK_WHOLE_SIZE); + VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack) + .sType$Default() + .pBufferMemoryBarriers(BufferBarrier); + vkCmdPipelineBarrier2(CommandHandle, DependencyInfo); + } + + public static void BufferBarriers(MemoryStack MemStack,VkCommandBuffer CommandHandle,long[] Buffers, + long SrcStage,long DstStage,long SrcAccess,long DstAccess ){ + var BufferBarriers = VkBufferMemoryBarrier2.calloc(Buffers.length, MemStack); + for (int i = 0; i < Buffers.length; i++) { + BufferBarriers.get(i) + .sType$Default() + .srcStageMask(SrcStage) + .dstStageMask(DstStage) + .srcAccessMask(SrcAccess) + .dstAccessMask(DstAccess) + .srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .buffer(Buffers[i]) + .offset(0) + .size(VK_WHOLE_SIZE); + } + VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack) + .sType$Default() + .pBufferMemoryBarriers(BufferBarriers); + + vkCmdPipelineBarrier2(CommandHandle, DependencyInfo); + } + public static void ImageBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long Image, int OldLayout, int NewLayout, long SrcStage, long DstStage, long SrcAccess, long DstAccess, int AspectMask){