#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 hash21(uvec2 p) { p = p * 1664525u + 1013904223u; p.x += p.y * 1664525u; p.y += p.x * 1664525u; return p.x ^ (p.x >> 16); } uint random_1_to_3(vec2 uv, uint customSeed) { uvec2 p = uvec2(floatBitsToUint(uv.x), floatBitsToUint(uv.y)); p.x ^= customSeed; uint randInt = hash21(p); return (randInt % 3u) + 1u; } uint packFace(uvec3 voxelPos, uint faceIndex, uint materialId) { uint randomFaceValue = random_1_to_3(vec2(voxelPos.x, voxelPos.z),faceOffset); uint textureIndexX = 0u; uint textureIndexY = 0u; if(materialId == 1u){ if(faceIndex == 0u){ textureIndexX = 0u; textureIndexY = randomFaceValue; } else if(faceIndex == 1u){ textureIndexX = 1u; textureIndexY = 0u; } else{ textureIndexX = 0u; textureIndexY = 0u; } } else if(materialId == 2u){ textureIndexX = 1u; textureIndexY = 0u; }else if(materialId == 3u){ textureIndexX = 1u; textureIndexY = 0u; }else if(materialId == 4u){ textureIndexX = 1u; textureIndexY = randomFaceValue; }else if(materialId == 5u){ textureIndexX = 2u; textureIndexY = 3u; }else if(materialId == 5u){ if (faceIndex == 0u || faceIndex == 1u){ textureIndexX = 2u; textureIndexY = 1u; } else{ textureIndexX = 2u; textureIndexY = 2u; } }else if(materialId == 6u){ textureIndexX = 2u; textureIndexY = 0u; } return (voxelPos.x & 0x1Fu) | ((voxelPos.y & 0x1Fu) << 5u) | ((voxelPos.z & 0x1Fu) << 10u) | ((faceIndex & 0x7u) << 15u) | ((materialId & 0xFFu) << 18u) | ((textureIndexX & 0x7u) << 26u) | ((textureIndexY & 0x7u) << 29u); } 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); 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 (current == 4u) { emitFace(pos, 6u, current); emitFace(pos, 7u, current); return; } if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u || getVoxel(pos + ivec3( 0, 1, 0)) == 4u) emitFace(pos, 0u, current); if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u || getVoxel(pos + ivec3( 0, -1, 0)) == 4u) emitFace(pos, 1u, current); if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u || getVoxel(pos + ivec3( 1, 0, 0)) == 4u) emitFace(pos, 2u, current); if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u || getVoxel(pos + ivec3( -1, 0, 0)) == 4u) emitFace(pos, 3u, current); if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u|| getVoxel(pos + ivec3( 0, 0, 1)) == 4u) emitFace(pos, 4u, current); if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u || getVoxel(pos + ivec3( 0, 0, -1)) == 4u) emitFace(pos, 5u, current); }