Creates a solver. Settings not given use DEFAULT_MPM. capacity, resolution, cellSize and which
materials are compiled in are fixed at construction; everything else is live through set.
ReadonlybuffersGPU buffers.
ReadonlycapacityMost particles.
Live particles (at most capacity; the oldest are overwritten when full).
ReadonlymaterialsMaterial names compiled in, by index.
ReadonlyobjectAdd this to your scene. It sits at origin; particle positions are local to it.
Resolved settings.
ReadonlyparamsPer material: its parameters as uniforms, and particle mass in normalised units.
ReadonlyparticlesThe particle pool (its buffers hold position, velocity and props; it draws them).
ReadonlyresolutionGrid nodes along x, y, z.
Substeps of the last MPMSolver.step.
Simulated seconds.
ReadonlyuniformsShader uniforms.
Colliders in use (see MPMSolver.setColliders).
Substep, seconds.
Δx.
Coulomb friction.
Gravity.
1/Δx.
Speed limit.
Domain move, metres (applied by the shift pass).
Colour ramp: key = 0.5 + (J − 1) × strainScale.
−dt / (2000·Δx²): P2G stress factor in normalised momentum units.
Domain walls on (1) or off (0).
Moves the domain so it is centred on a world position (e.g. the camera), by whole cells and only once the position is more than a quarter of the domain off centre. Particles keep their world positions.
Removes every particle.
Removes the mesh and frees the GPU passes.
MPMSolver.step's compute passes for dt, to batch with other work in one renderer.compute([...]).
Reads the particle state back from the GPU (slow; for tests, debugging and tools).
Merges input into the settings. Structural settings (see the constructor) are kept, with a warning.
Optionalcapacity?: numberMost particles. Fixed at construction.
OptionalcellSize?: numberGrid spacing Δx, metres. Particles are emitted 2 per cell per axis (8 per cell). Fixed at construction.
Optionalcfl?: numberCourant number C of the stable step dt ≤ C·Δx / (maxSpeed + sound speed) (see mpmStableStep).
Optionalfriction?: numberTerrain friction coefficient (Coulomb): 0 slips, large values stick.
Optionalgravity?: [number, number, number]Gravity, m/s².
Optionalmaterials?: { [key: string]: { [key: string]: number | undefined } | undefined }Materials compiled in (keys, fixed at construction) and their parameters (live).
OptionalmaxSpeed?: numberParticle speed limit, m/s: the "max particle speed" of the stable step, enforced in G2P.
OptionalmaxSubsteps?: numberMost substeps per frame; past it the simulation runs slower than real time instead of going unstable.
Optionalorigin?: [number, number, number]World position of the domain's minimum corner, metres. Moving it shifts the domain by whole cells (the particles keep their world positions; those left outside freeze). Floating-origin safe: the GPU only sees positions relative to it.
Optionalrender?: { colors?: string[]; opacity?: number; size?: number; strainScale?: number }Drawing through the particle pool's unlit shading.
Optionalcolors?: string[]Colour ramp by volume change J: first key squashed, middle at rest, last stretched (1 to 8 #rrggbb).
Optionalopacity?: numberOpacity.
Optionalsize?: numberSprite width, in particle spacings (Δx / 2).
OptionalstrainScale?: numberHow much volume change spans the colour ramp: key = 0.5 + (J − 1) × strainScale.
Optionalresolution?: [number, number, number]Grid nodes along x, y, z (8…160 each). Fixed at construction.
Optionalseed?: string | numberSeed for the emission jitter.
Optionalsubsteps?: numberSubsteps per frame at least. More are added when the frame is longer than the stable step allows.
Optionalwalls?: booleanDomain sides act as slip walls (else particles that leave the domain freeze).
Sets the kinematic colliders (spheres or capsules, world metres; at most MPM_MAX_COLLIDERS), e.g. feet or
wheels, each frame as they move. Give them their velocity so they push material along (footprints, tracks).
Scales the terrain friction by friction(x, z) (world metres, ≥ 0) per node column, e.g. a weak layer under a
slab that releases while the snow around it holds. Re-baked when the domain moves; null for 1 everywhere.
Replaces the terrain height function (re-baked at the node columns); null removes the ground.
Advances dt seconds (capped at 0.1) on the GPU in substeps: P2G, grid update (which also clears the
accumulators) and G2P each. Needs the WebGPU backend; on WebGL the particles hide themselves.
A real-time MLS-MPM solver (moving least squares material point method, Hu et al. 2018) on WebGPU compute: APIC transfers with quadratic B-splines over 3×3×3 nodes, fixed-point atomic P2G (deterministic), a grid update with gravity, domain walls and a terrain height-function boundary with Coulomb friction, and G2P advection with a per-material stress and plasticity hook. Several substeps per frame at a stable time step. The domain is a fixed-size grid placed anywhere (
origin, or MPMSolver.center to follow the camera); particles outside it freeze.Particles live in a ParticleSystem pool and draw through its unlit shading, coloured by volume change. Materials come from the registry (registerMPMMaterial); the core ships
jelly.Example