3D Particle Network
Generating Universe...
Initializing WebGPU
Algorithm: GPU hash-grid neighbor search with O(n) complexity
Generation: Seed-based procedural (cosmic)
Rendering: WebGPU compute shaders + instanced particles
About This Simulation
This is a GPU-accelerated 3D particle network that demonstrates advanced WebGPU compute shader techniques. The entire simulation runs on the GPU, from physics calculations to culling optimizations, achieving 10,000+ particles at 60fps.
Key Features
- Full GPU Compute: All physics calculations happen in WGSL compute shaders
- O(n) Neighbor Search: Hash-grid spatial partitioning eliminates quadratic complexity
- Dynamic Connectivity: Edges are generated in real-time based on particle proximity
- GPU Frustum Culling: Only visible particles are rendered using compaction + indirect draw
- Zero-Copy Rendering: Compute shaders write directly to vertex buffers
Algorithm: Spatial Hash Grid
Traditional particle simulations use O(n²) algorithms where every particle checks every other particle. This becomes prohibitively expensive beyond a few hundred particles.
Instead, we use a uniform spatial hash grid that reduces complexity to O(n):
Grid Construction (6 compute passes)
- Clear: Zero all cell counters
- Histogram: Count particles per cell (atomic operations)
- Prefix Sum: Compute offsets for each cell
- Stage 1: Scan within workgroups (256 elements)
- Stage 2: Scan chunk sums
- Stage 3: Add scanned sums back to chunks
- Scatter: Write particle indices to sorted cell lists
Force Calculation (1 fused pass)
For each particle:
- Determine grid cell:
cell = floor(position / cell_size) - Walk 27 neighbor cells (3×3×3 cube)
- For each nearby particle:
- Attraction: Pulls particles together
- Repulsion: Prevents overlap (inverse square)
- Edge Generation: Create edge when distance < threshold and i < j
Physics Integration (1 pass)
- Apply velocity damping
- Euler integration:
position += velocity * dt - Spherical boundary collision with reflection
Visibility Culling (1 pass)
- Test each particle against 6 frustum planes
- Workgroup-local prefix sum of visibility flags
- Compact visible particle indices
- Write indirect draw arguments
Rendering Pipeline
Particles
Rendered as instanced icospheres with per-particle position, size, and color. Uses:
- Blinn-Phong shading for realistic lighting
- Distance fog for depth perception
- Color-coded connectivity: Warmer colors = more neighbors
Edges
Rendered as screen-space quads (not lines) for consistent thickness across devices:
- Vertex shader fetches edge endpoints from storage buffer
- Projects to NDC and computes perpendicular direction
- Expands to quad with desired pixel thickness
- Fragment shader applies transparency based on edge strength
Performance Characteristics
| Particles | FPS | Edges | GPU Time |
|---|---|---|---|
| 1,000 | 60 | ~8k | ~2ms |
| 5,000 | 60 | ~40k | ~8ms |
| 10,000 | 60 | ~80k | ~15ms |
| 20,000 | 45 | ~150k | ~25ms |
Tested on M1 Pro (16-core GPU)
Bottlenecks
- Edge rendering: Transparent quads require sorting or overdraw
- Grid construction: 6 passes have overhead
- Neighbor iteration: 27 cells × avg particles per cell
Optimizations Applied
- ✅ Cell size ≈ connection distance (minimizes false positives)
- ✅ Fused forces + connectivity (one neighbor walk)
- ✅ Zero-copy instance buffer (STORAGE + VERTEX usage)
- ✅ Frustum culling with compaction
- ✅ Indirect draw (GPU-driven instance count)
Math Details
Frustum Plane Extraction
From view-projection matrix VP, extract 6 planes:
Left: VP.row4 + VP.row1
Right: VP.row4 - VP.row1
Bottom: VP.row4 + VP.row2
Top: VP.row4 - VP.row2
Near: VP.row4 + VP.row3
Far: VP.row4 - VP.row3
Each plane is normalized: plane.xyz /= length(plane.xyz)
Prefix Sum (Blelloch Algorithm)
Upsweep (reduce):
for d = N/2 down to 1:
for k = 0 to d-1:
temp[2k+2d-1] += temp[2k+d-1]
Downsweep (distribute):
temp[N-1] = 0 // Exclusive scan
for d = 1 to N/2:
for k = 0 to d-1:
swap temp[2k+d-1] and temp[2k+2d-1]
temp[2k+2d-1] += temp[2k+d-1]
Forces
Attraction (spring-like):
F_attract = direction * k_attract
Repulsion (inverse-square):
F_repel = -direction * k_repel / (r² + ε)
Browser Compatibility
| Browser | Support | Notes |
|---|---|---|
| Chrome 113+ | ✅ | Full support |
| Edge 113+ | ✅ | Full support |
| Safari 26+ | ✅ | macOS/iOS/iPadOS/visionOS |
| Firefox 141+ | ⚠️ | Supported on Windows, platform coverage maturing |
Firefox WebGPU
Firefox 141+ (July 2025) ships with production WebGPU support on Windows. On other platforms, WebGPU may require enabling via about:config:
- Type
about:configin the address bar - Search for
dom.webgpu.enabled - Toggle to
trueand restart Firefox
Note: Platform coverage is still maturing; Windows users should have full support out of the box.
Technical Specifications
- Language: Rust (WASM) + TypeScript + WGSL
- Graphics API: WebGPU
- Compute Shaders: 9 (grid construction, forces, integration, culling)
- Render Pipelines: 2 (particles, edges)
- Buffer Usage: ~8MB for 10k particles
- Dependencies: wgpu, glam, bytemuck, wasm-bindgen
Source Code
- Rust Core:
simulations/particle-network-3d/src/ - WGSL Shaders:
simulations/particle-network-3d/src/shaders/ - TypeScript App:
simulations/particle-network-3d/src/app.ts - React Wrapper:
src/components/simulations/ParticleNetwork3D.tsx
Extensions
This codebase can be adapted for:
- Force-Directed Graphs: Replace distance-based forces with spring forces on edges
- Molecular Dynamics: Implement Lennard-Jones potential
- 3D Boids: Add alignment, cohesion, separation rules
- SPH Fluids: Two-pass density-pressure calculation
References
- WebGPU Spec
- WGSL Spec
- Parallel Prefix Sum (GPU Gems 3)
- Spatial Hashing for Neighbor Search
- GPU Frustum Culling
Controls
- Left drag: Orbit camera around center
- Right drag: Pan camera
- Scroll: Zoom in/out
- Auto-rotate: Optional automatic rotation
Built with WebGPU, Rust, and WASM. Requires Chrome 113+ or Edge 113+.