Design & Brand Philosophy

Procedural Mesh Generation: Dual Marching Cubes & Iso-Surfaces in WebGPU

By Creative Direction Team

Procedurally generating complex volumetric terrain, fluid surfaces, and CAD geometry inside the browser has historically been constrained by CPU-bound polygon extraction. WebGPU compute pipelines revolutionize procedural generation by porting Dual Marching Cubes (DMC) and Surface Nets directly onto the GPU. By sampling 3D signed distance fields (SDFs) across threadgroups and utilizing atomic stream compaction, WebGPU constructs indexed triangle buffers entirely in VRAM without CPU readbacks.

The Architecture of Dual Marching Cubes on WebGPU

How dual grid topology preserves sharp geometric features and eliminates manifold holes:

📐 The Dual Vertex Feature Invariant

Standard Marching Cubes places vertices along voxel edges, resulting in rounded corners and degenerate sliver triangles. Dual Marching Cubes constructs dual vertices inside voxel cells using Quadratic Error Functions (QEF). Connecting dual vertices across active sign-changing edges preserves sharp mechanical creases while guaranteeing 2-manifold closed surface meshes.

Iso-Surface Extraction Algorithms Compared

Extraction Algorithm Sharp Feature Preservation GPU Compute Parallelism Triangle Topology Quality
Classic Marching Cubes (Lorensen)Poor (Smooth chamfers only)High ($O(N^3)$ independent cells)Sub-optimal (Sliver triangles)
Dual Contouring (Ju et al.)Optimal (QEF feature vertices)Moderate (Octree traversal overhead)High (Adaptive quads)
WebGPU Dual Marching CubesHigh (Manifold preserving)Maximum (Atomic Stream Compaction)Balanced Triangulation

WGSL Compute Shader Atomic Mesh Compaction

Writing extracted vertices and indices to GPU storage buffers:

struct MeshCounter {
  vertexCount: atomic<u32>,
  indexCount: atomic<u32>,
};

@group(0) @binding(0) var<storage, read_write> counter: MeshCounter;
@group(0) @binding(1) var<storage, read_write> vertexBuffer: array<vec4<f32>>;
@group(0) @binding(2) var<storage, read_write> indexBuffer: array<u32>;

@compute @workgroup_size(8, 8, 8)
fn computeDualIsoSurface(@builtin(global_invocation_id) id: vec3<u32>) {
  // Sample SDF volume at voxel corners
  let cellActive = evaluateVoxelIntersection(id);
  if (!cellActive) { return; }

  // Atomic allocation for vertex and triangle indices
  let baseVertIndex = atomicAdd(&counter.vertexCount, 1u);
  let baseIdxIndex = atomicAdd(&counter.indexCount, 3u);

  vertexBuffer[baseVertIndex] = calculateQEFVertex(id);
  indexBuffer[baseIdxIndex + 0u] = baseVertIndex;
  indexBuffer[baseIdxIndex + 1u] = baseVertIndex + 1u;
  indexBuffer[baseIdxIndex + 2u] = baseVertIndex + 2u;
}

Explore Advanced Real-Time Graphics & Compute

Master cutting-edge GPU rendering pipelines in WebGPU. Read our guide on WebGPU Vertex Pulling & Programmable Assembly, explore CXL NUMA cloud tiering on WinWinHost CXL Infrastructure, review custom memory allocators on WebDesigner.la jemalloc Tuning, or consult with our real-time graphics architects.