GPU Physics Engine
WebGPU compute-based physics engine with full PhysX 5.4.1 feature parity.
15 modules in engine/sim/physics/gpu/, ~400KB total.
All shaders written in WGSL. No PhysX code modified — parallel implementation for future migration.
PhysX 5 Audit Complete. Every GPU-accelerated feature in PhysX 5.4.1 (rigid bodies, broadphase, contact gen, solver, CCD, vehicles, CCT, soft bodies, triggers, scene queries, heightfield, triangle mesh) is covered by a dedicated module. See the full parity table below.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ GPU Physics Pipeline │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
│ │ CCD │→ │Broadphase│→ │Narrowphase│→ │ Solver │ │
│ │ Expand │ │ (Hash) │ │ (PCM) │ │ (TGS_Soft)│ │
│ └──────────┘ └──────────┘ └───────────┘ └──────────┘ │
│ ↓ ↓ ↓ ↓ │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
│ │Heightfield│ │TriMesh │ │ Triggers │ │Integration│ │
│ │ Contacts │ │ Contacts │ │ Events │ │ + Sleep │ │
│ └──────────┘ └──────────┘ └───────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
│ │ Vehicles │ │ Soft Body│ │ CCT │ │ Readback │ │
│ │ (GPU) │ │ (FEM) │ │ (CPU) │ │ (Async) │ │
│ └──────────┘ └──────────┘ └───────────┘ └──────────┘ │
│ │
│ CPU-side queries (synchronous): │
│ ┌──────────┐ ┌──────────┐ │
│ │ Raycast │ │ Scene │ │
│ │ (CPU/GPU)│ │ Query │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
Key Principles
- WebGPU compute shaders (WGSL) for all parallel workloads
- CPU orchestration for serial logic (islands, CCT, scene queries)
- Fixed pre-allocated GPU buffers (PhysX 5 pattern) — overflow warns, never crashes
- SoA (Structure of Arrays) layout for GPU cache efficiency
- No PhysX code modified — parallel implementation, future migration
PhysX 5 Feature Parity
Audited against PhysX 5.4.1 (nvidia-omniverse.github.io/PhysX/physx/5.4.1/).
GPU Physics Modules (15 files)
| PhysX 5 Feature | Our Module | Status |
|---|---|---|
| GPU Rigid Bodies | GPURigidBodyWorld.js | Built |
| GPU Broadphase | GPUBroadphase.js | Built |
| GPU Contact Gen (PCM) | GPUNarrowphase.js | Built |
| GPU Constraint Solver (TGS) | GPUConstraintSolver.js | Built |
| Convex Hull Cooking | GPUConvexHull.js | Built |
| Raycasting | GPURaycast.js | Built |
| Speculative CCD | GPUContinuousCollision.js | Built |
| Vehicle SDK | GPUVehicle.js | Built |
| Character Controller | GPUCharacterController.js | Built |
| FEM Soft Bodies | GPUSoftBody.js | Built |
| Trigger Events | GPUTriggerSystem.js | Built |
| Scene Queries | GPUSceneQuery.js | Built |
| Heightfield Terrain | GPUHeightfield.js | Built |
| Triangle Mesh Collider | GPUTriangleMesh.js | Built |
Existing Engine Systems (already built)
These modules in the parent engine/sim/physics/ directory already cover additional PhysX features. They are referenced from the GPU barrel export.
| Feature | Module | Notes |
|---|---|---|
| PBD Cloth | GPUClothSolver.js | Small substeps (Macklin 2019) + OGC contact |
| Articulations | GPUArticulationSolver.js | Cosserat rods, PBD stiff rods |
| SDF Mesh Geometry | SDFCollision.js | SDF grid, mesh-to-SDF (PhysX 5 style) |
| PBD Solver (XPBD) | PBDSolver.js | Distance / angle / volume, graph coloring |
| MLS-MPM Soft Body | MLSMPMSolver.js | Snow, sand, jelly, topology changes |
| OGC Contact | OGCContact.js | Penetration-free barrier (SIGGRAPH 2025) |
| CPU CCD | SpeculativeContacts.js | AABB expansion, time-of-closest-approach |
| Shock Propagation | ShockPropagation.js | Guendelman et al. SIGGRAPH 2003 |
| Destruction (Blast SDK) | VoronoiFracture.js + FragmentPhysics.js | Voronoi fracture + fragment manager |
| Convex Decomposition | ConvexDecomposition.js | V-HACD voxelization + decomposition |
| Voxel Mesh Collider | VoxelMeshCollision.js | GPU voxelized mesh collider with LOD |
| Spatial Hash (GPU) | GPUSpatialHash.js | Morton codes (GPU Gems 3 Ch.32) |
Features That Exceed PhysX 5
| Feature | Module | Why It's Unique |
|---|---|---|
| OGC Contact Model | OGCContact.js | SIGGRAPH 2025 — penetration-free barrier energy |
| MLS-MPM | MLSMPMSolver.js | Handles topology changes (melting, fracture) |
| LBM Wind | WindSimulation.js | Lattice Boltzmann GPU wind field |
| Thermal Particles | ParticleSimWorld.js | Phase transitions, buoyancy, chemistry |
| Rope Interaction | RopeParticleInteraction.js | Per-fiber thermal (burn, wet, corrode) |
Core Rigid Body Pipeline
GPURigidBodyWorld.js 55KB
Central world manager. Owns all GPU buffers, body descriptions, and the simulation island manager.
- 5 WGSL shaders — integrate, applyDeltas, deriveVelocity, sleepDetect, clearForces
- Island Manager — CPU union-find for body groups. Sleeping islands skip GPU dispatch
- SoA layout — positions, rotations, velocities, forces, colliders, flags as separate GPU buffers
- Body types — Dynamic (0), Kinematic (1), Static (2)
- Shapes — Sphere (0), Box (1), Capsule (2)
GPUBroadphase.js 22KB
Spatial hash broadphase. Outputs collision pair buffer for narrowphase.
- 4 WGSL shaders — computeAABB, clearHash, insertHash, findPairs
- 27-neighbor cell query with layer/mask filtering at pair level
GPUNarrowphase.js 30KB
Analytic shape-shape contact generation with persistent contact manifold (PCM).
- Pairs — sphere-sphere, sphere-box, box-box (SAT 15 axes), sphere-capsule, capsule-capsule, ground plane
- Contact data — normal, penetration, point, accumulated impulse, local anchors (A+B), featureId
GPUConstraintSolver.js 30KB
TGS_Soft iterative solver for contacts and joints (Box2D v3 / Catto 2023).
- Contact solve — Bias velocity, Coulomb friction cone, restitution, accumulated impulse clamping, warm starting
- Joint solve — D6 joint (native GPU, PhysX best practice): ball, hinge, fixed, distance, cone limits
- Relaxation pass — Post-solve smoothing for stability
GPUConvexHull.js 19KB
CPU-side Quickhull 3D + GPU buffer upload. PhysX 64-vertex GPU limit enforced.
GPURaycast.js 24KB
GPU parallel raycasting (ray-sphere/box/capsule) with workgroup reduction. CPU fallback for synchronous queries.
GPUContinuousCollision.js 18KB
Speculative CCD to prevent tunneling of fast bodies.
- Phase 1 — AABB expansion by velocity * dt for CCD-flagged bodies (bit 25)
- Phase 2 — TOI via conservative advancement, generates speculative contacts at predicted impact
Extended Simulation
GPUVehicle.js 27KB
Complete vehicle physics inspired by PhysX 5 Vehicle SDK.
- GPU shader — Per-wheel suspension (spring-damper) and tire force (simplified Pacejka)
- CPU manager — Vehicle creation, input handling, gear shifting (manual + auto)
- Presets — sedan, sports, truck, offroad
- Limits — MAX_VEHICLES=64, MAX_WHEELS_PER_VEHICLE=8, drive types FWD/RWD/AWD
GPUCharacterController.js 17KB
CPU-driven kinematic character controller (PhysX CCT equivalent).
- Movement — Quake-style recursive slide-move with deflection planes, max 4 bounces
- Ground detection — Downward raycast, skin width 0.08m, step height 0.35m
- Slope limit — ~45° default, slide down steep slopes
- Step climbing — Probe forward+up, auto-step onto geometry ≤ stepHeight
- Shapes — Capsule (default) or box
GPUSoftBody.js 30KB
FEM soft body simulation using tetrahedral meshes (PhysX 5 signature feature).
- 2 GPU shaders — FEM Force (per-tet deformation gradient, co-rotational elasticity) + Integration
- Polar decomposition — Müller iterative extraction, handles large deformation
- Materials — Young's modulus + Poisson's ratio → Lamé parameters (μ, λ)
- Presets — rubber (1MPa), jelly (50KPa), flesh (100KPa), foam (20KPa), silicone (500KPa), stiff (10MPa)
GPUTriggerSystem.js 22KB
Trigger volumes and contact event system (PhysX PxSimulationEventCallback equivalent).
- GPU shader — AABB overlap for trigger-flagged bodies (bit 24) vs non-triggers
- CPU tracking — Persistent pair state for enter/stay/exit detection
- Callbacks — onTriggerEnter, onTriggerStay, onTriggerExit, onContactBegin, onContactPersist, onContactEnd
Geometry & Queries
GPUSceneQuery.js 19KB
CPU-side synchronous scene queries. Scene queries are typically 1-10 per frame and need immediate results, so GPU readback latency would negate the benefit.
- Overlap — overlapSphere, overlapBox, overlapSphereAny, overlapBoxAny
- Sweep — sweepSphere, sweepBox, sweepSphereAll (multi-hit)
- Filtering — layerMask, excludeBody, includeSleeping, includeStatic, includeTriggers, entityIds
GPUHeightfield.js 19KB
Heightmap-based terrain collider (PhysX PxHeightField equivalent).
- GPU shader — 5-point sampling (center + 4 footprint corners) with bilinear interpolation
- Per-cell materials — Surface type queries (grass, rock, mud)
- Holes — Cells with height = NaN are passthrough
- Limits — Up to 1024×1024 grid
GPUTriangleMesh.js 25KB
Static triangle mesh collider with BVH traversal (PhysX PxTriangleMeshGeometry equivalent).
- CPU cook — buildTriangleMeshBVH: median-split BVH, packed for GPU
- GPU shader — Per-body iterative BVH traversal (32-level stack), closest-point-on-triangle, 8 contacts/body
- Multi-mesh — Up to 16 registered meshes, each with independent BVH
- Limits — 65536 triangles per mesh
Constants & Limits
| Constant | Value | Module |
|---|---|---|
MAX_BODIES | 4096 | GPURigidBodyWorld |
MAX_CONTACTS | 16384 | GPUNarrowphase (shared) |
MAX_PAIRS | 32768 | GPUBroadphase |
MAX_JOINTS | 2048 | GPUConstraintSolver |
MAX_VEHICLES | 64 | GPUVehicle |
MAX_WHEELS_PER_VEHICLE | 8 | GPUVehicle |
MAX_TRIGGER_EVENTS | 4096 | GPUTriggerSystem |
MAX_CCD_PAIRS | 8192 | GPUContinuousCollision |
MAX_SOFT_BODY_NODES | 16384 | GPUSoftBody |
MAX_SOFT_BODY_TETS | 32768 | GPUSoftBody |
MAX_TRIMESH_TRIANGLES | 65536 | GPUTriangleMesh |
MAX_TRIMESH_INSTANCES | 16 | GPUTriangleMesh |
MAX_HEIGHTFIELD_SIZE | 1024 | GPUHeightfield |
All limits are configurable via constructor options. PhysX 5 GPU pattern: fixed pre-allocated buffers with overflow warnings.
Pipeline Execution Order
Each physics frame should dispatch in this order:
- CCD Expand AABBs —
GPUContinuousCollision.dispatchExpand - Broadphase —
GPUBroadphase.dispatch - Narrowphase —
GPUNarrowphase.dispatch - Heightfield Contacts —
GPUHeightfield.dispatch - Triangle Mesh Contacts —
GPUTriangleMesh.dispatch - CCD TOI Contacts —
GPUContinuousCollision.dispatchTOI - Constraint Solver —
GPUConstraintSolver.dispatch - Integration + Sleep —
GPURigidBodyWorld.dispatchIntegration - Trigger & Contact Events —
GPUTriggerSystem.dispatch + processEvents - Vehicle Forces —
GPUVehicleManager.dispatch - Soft Body Step —
GPUSoftBody.step - Character Controller —
CharacterControllerManager.updateAll - Readback —
GPURigidBodyWorld.readbackPositions
Scene queries and raycasts can be called at any time (CPU-side, synchronous).
Design Decisions
| Decision | Rationale | Source |
|---|---|---|
| TGS_Soft solver | Sub-stepping + warm starting + soft constraints | Box2D v3 (Catto 2023) |
| Delta-position formulation | FP32 stability far from world origin | Erin Catto GDC 2024 |
| Simulation islands (CPU) | Union-find groups for per-island sleep/wake | Jolt, PhysX 5 |
| D6 as sole GPU joint | All types decompose to D6 — one shader | PhysX 5 GPU best practice |
| Spatial hash broadphase | O(1) insert/query, good GPU utilization | GPU Gems 3 Ch.32 |
| Fixed buffers | Pre-allocated, overflow warnings, no runtime alloc | PhysX 5 GPU pattern |
| PCM contacts | Persistent manifold + local anchors + feature IDs | PhysX 5 eENABLE_PCM |
| CPU scene queries | 1-10 queries/frame need synchronous results | PhysX 5 architecture |
| CPU character controller | Latency-sensitive input, kinematic sweep tests | PhysX 5 CCT |
| Co-rotational FEM | Stable under large deformation, cheaper than Neo-Hookean | Müller, Irving et al. |
| BVH for triangle mesh | Median-split AABB tree, iterative GPU traversal | Embree, PhysX buildGPUData |
File Listing
engine/sim/physics/gpu/
├── GPURigidBodyWorld.js 55KB Core world + integration
├── GPUBroadphase.js 22KB Spatial hash broadphase
├── GPUNarrowphase.js 30KB Shape-shape contacts (PCM)
├── GPUConstraintSolver.js 30KB TGS_Soft solver + D6 joints
├── GPUConvexHull.js 19KB Quickhull 3D + GPU upload
├── GPURaycast.js 24KB GPU parallel raycast
├── GPUContinuousCollision.js 18KB Speculative CCD
├── GPUVehicle.js 27KB Vehicle physics
├── GPUCharacterController.js 17KB Kinematic CCT
├── GPUSoftBody.js 30KB FEM soft body (tetrahedral)
├── GPUTriggerSystem.js 22KB Triggers + contact events
├── GPUSceneQuery.js 19KB Overlap / sweep queries
├── GPUHeightfield.js 19KB Terrain heightfield
├── GPUTriangleMesh.js 25KB Static mesh collider (BVH)
└── index.js 3KB Barrel export
─────
~400KB total
References
Academic
- Erin Catto — "Solver2D" (Box2D v3), GDC 2023-2024
- Miles Macklin — "Small Steps in Physics Simulation", NVIDIA 2019
- Müller et al. — "Real Time Physics", SIGGRAPH Course
- Irving et al. — "Invertible Finite Elements for Robust Simulation", SIGGRAPH 2004
- Smith et al. — "Stable Neo-Hookean Flesh Simulation", SIGGRAPH 2018
- Guendelman et al. — "Nonconvex Rigid Bodies with Stacking", SIGGRAPH 2003
- Chen et al. — "Offset Geometric Contact", SIGGRAPH 2025
- Erwin Coumans — "Speculative Contacts", GDC 2013
Engine
- PhysX 5.4.1 Documentation —
nvidia-omniverse.github.io/PhysX/physx/5.4.1/ - PhysX 5 GitHub —
github.com/NVIDIA-Omniverse/PhysX - Jolt Physics —
github.com/jrouwe/JoltPhysics - Rapier —
rapier.rs - GPU Gems 3, Chapter 32 — "Broad-Phase Collision Detection with CUDA"
- GPU Gems 3, Chapter 29 — "Real-Time Rigid Body Simulation on GPUs"