#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 VERTICES_PER_FACE = 6u; const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * 6); layout(std430, binding = 0) readonly buffer VoxelData { uint voxels[]; }; layout(std430, binding = 1) buffer FaceBuffer { uint faces[]; }; struct DrawCommand { uint vertexCount; uint instanceCount; uint firstVertex; uint firstInstance; }; layout(std430, binding = 2) buffer DrawCommands { DrawCommand drawCmds[]; }; layout(std430, binding = 3) buffer Counters { uint faceCount; } counters; layout(push_constant) uniform ChunkInfo { ivec3 chunkPos; int slot; uint faceOffset; uint unused0; uint indirectCommandIndex; uint 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 0u; if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0u; if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0u; return voxels[flatten(pos)]; } uint packFace(uvec3 voxelPos, uint faceIndex, uint materialId, uint ao) { return (voxelPos.x & 0x1Fu) | ((voxelPos.y & 0x1Fu) << 5u) | ((voxelPos.z & 0x1Fu) << 10u) | ((faceIndex & 0x7u) << 15u) | ((materialId & 0xFFu) << 18u) | ((ao & 0x3u) << 26u); } void emitFace(ivec3 voxelPos, uint faceIndex, uint voxelType) { uint localFace = atomicAdd(counters.faceCount, 1u); if (localFace >= MAX_VISIBLE_FACES_PER_CHUNK) { return; } faces[faceOffset + localFace] = packFace(uvec3(voxelPos), faceIndex, voxelType, 0u); atomicAdd(drawCmds[indirectCommandIndex].vertexCount, VERTICES_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, 0u, current); if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1u, current); if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2u, current); if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3u, current); if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4u, current); if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5u, current); }