struct Tables { edges : array; tris : array; } @group(0) @binding(0) var tables : Tables; struct IsosurfaceVolume { min : vec3; max : vec3; step : vec3; size : vec3; threshold : f32; values : array; } @group(0) @binding(1) var volume : IsosurfaceVolume; struct PositionBuffer { values : array; } @group(0) @binding(2) var positionsOut : PositionBuffer; struct NormalBuffer { values : array; } @group(0) @binding(3) var normalsOut : NormalBuffer; struct IndexBuffer { tris : array; } @group(0) @binding(4) var indicesOut : IndexBuffer; struct DrawIndirectArgs { vc : u32; vertexCount : atomic; firstVertex : u32; firstInstance : u32; indexCount : atomic; indexedInstanceCount : u32; indexedFirstIndex : u32; indexedBaseVertex : u32; indexedFirstInstance : u32; } @group(0) @binding(5) var drawOut : DrawIndirectArgs; fn valueAt(index : vec3) -> f32 { if (any((index >= volume.size))) { return 0.0; } let valueIndex = ((index.x + (index.y * volume.size.x)) + ((index.z * volume.size.x) * volume.size.y)); return volume.values[valueIndex]; } fn positionAt(index : vec3) -> vec3 { return (volume.min + (volume.step * vec3(index.xyz))); } fn normalAt(index : vec3) -> vec3 { return vec3((valueAt((index - vec3(1u, 0u, 0u))) - valueAt((index + vec3(1u, 0u, 0u)))), (valueAt((index - vec3(0u, 1u, 0u))) - valueAt((index + vec3(0u, 1u, 0u)))), (valueAt((index - vec3(0u, 0u, 1u))) - valueAt((index + vec3(0u, 0u, 1u))))); } var positions : array, 12>; var normals : array, 12>; var indices : array; var cubeVerts : u32 = 0u; fn interpX(index : u32, i : vec3, va : f32, vb : f32) { let mu = ((volume.threshold - va) / (vb - va)); positions[cubeVerts] = (positionAt(i) + vec3((volume.step.x * mu), 0.0, 0.0)); let na = normalAt(i); let nb = normalAt((i + vec3(1u, 0u, 0u))); normals[cubeVerts] = mix(na, nb, vec3(mu, mu, mu)); indices[index] = cubeVerts; cubeVerts = (cubeVerts + 1u); } fn interpY(index : u32, i : vec3, va : f32, vb : f32) { let mu = ((volume.threshold - va) / (vb - va)); positions[cubeVerts] = (positionAt(i) + vec3(0.0, (volume.step.y * mu), 0.0)); let na = normalAt(i); let nb = normalAt((i + vec3(0u, 1u, 0u))); normals[cubeVerts] = mix(na, nb, vec3(mu, mu, mu)); indices[index] = cubeVerts; cubeVerts = (cubeVerts + 1u); } fn interpZ(index : u32, i : vec3, va : f32, vb : f32) { let mu = ((volume.threshold - va) / (vb - va)); positions[cubeVerts] = (positionAt(i) + vec3(0.0, 0.0, (volume.step.z * mu))); let na = normalAt(i); let nb = normalAt((i + vec3(0u, 0u, 1u))); normals[cubeVerts] = mix(na, nb, vec3(mu, mu, mu)); indices[index] = cubeVerts; cubeVerts = (cubeVerts + 1u); } @stage(compute) @workgroup_size(4, 4, 4) fn computeMain(@builtin(global_invocation_id) global_id : vec3) { let i0 = global_id; let i1 = (global_id + vec3(1u, 0u, 0u)); let i2 = (global_id + vec3(1u, 1u, 0u)); let i3 = (global_id + vec3(0u, 1u, 0u)); let i4 = (global_id + vec3(0u, 0u, 1u)); let i5 = (global_id + vec3(1u, 0u, 1u)); let i6 = (global_id + vec3(1u, 1u, 1u)); let i7 = (global_id + vec3(0u, 1u, 1u)); let v0 = valueAt(i0); let v1 = valueAt(i1); let v2 = valueAt(i2); let v3 = valueAt(i3); let v4 = valueAt(i4); let v5 = valueAt(i5); let v6 = valueAt(i6); let v7 = valueAt(i7); var cubeIndex = 0u; if ((v0 < volume.threshold)) { cubeIndex = (cubeIndex | 1u); } if ((v1 < volume.threshold)) { cubeIndex = (cubeIndex | 2u); } if ((v2 < volume.threshold)) { cubeIndex = (cubeIndex | 4u); } if ((v3 < volume.threshold)) { cubeIndex = (cubeIndex | 8u); } if ((v4 < volume.threshold)) { cubeIndex = (cubeIndex | 16u); } if ((v5 < volume.threshold)) { cubeIndex = (cubeIndex | 32u); } if ((v6 < volume.threshold)) { cubeIndex = (cubeIndex | 64u); } if ((v7 < volume.threshold)) { cubeIndex = (cubeIndex | 128u); } let edges = tables.edges[cubeIndex]; if (((edges & 1u) != 0u)) { interpX(0u, i0, v0, v1); } if (((edges & 2u) != 0u)) { interpY(1u, i1, v1, v2); } if (((edges & 4u) != 0u)) { interpX(2u, i3, v3, v2); } if (((edges & 8u) != 0u)) { interpY(3u, i0, v0, v3); } if (((edges & 16u) != 0u)) { interpX(4u, i4, v4, v5); } if (((edges & 32u) != 0u)) { interpY(5u, i5, v5, v6); } if (((edges & 64u) != 0u)) { interpX(6u, i7, v7, v6); } if (((edges & 128u) != 0u)) { interpY(7u, i4, v4, v7); } if (((edges & 256u) != 0u)) { interpZ(8u, i0, v0, v4); } if (((edges & 512u) != 0u)) { interpZ(9u, i1, v1, v5); } if (((edges & 1024u) != 0u)) { interpZ(10u, i2, v2, v6); } if (((edges & 2048u) != 0u)) { interpZ(11u, i3, v3, v7); } let triTableOffset = ((cubeIndex << 4u) + 1u); let indexCount = u32(tables.tris[(triTableOffset - 1u)]); var firstVertex = atomicAdd(&(drawOut.vertexCount), cubeVerts); let bufferOffset = ((global_id.x + (global_id.y * volume.size.x)) + ((global_id.z * volume.size.x) * volume.size.y)); let firstIndex = (bufferOffset * 15u); for(var i = 0u; (i < cubeVerts); i = (i + 1u)) { positionsOut.values[((firstVertex * 3u) + (i * 3u))] = positions[i].x; positionsOut.values[(((firstVertex * 3u) + (i * 3u)) + 1u)] = positions[i].y; positionsOut.values[(((firstVertex * 3u) + (i * 3u)) + 2u)] = positions[i].z; normalsOut.values[((firstVertex * 3u) + (i * 3u))] = normals[i].x; normalsOut.values[(((firstVertex * 3u) + (i * 3u)) + 1u)] = normals[i].y; normalsOut.values[(((firstVertex * 3u) + (i * 3u)) + 2u)] = normals[i].z; } for(var i = 0u; (i < indexCount); i = (i + 1u)) { let index = tables.tris[(triTableOffset + i)]; indicesOut.tris[(firstIndex + i)] = (firstVertex + indices[index]); } for(var i = indexCount; (i < 15u); i = (i + 1u)) { indicesOut.tris[(firstIndex + i)] = firstVertex; } }