#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); }