threejs-worldgen
    Preparing search index...

    Class MPMSolver

    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.

    const mpm = new MPMSolver(renderer, { origin: [-8, 0, -8], height: (x, z) => world.height(x, z) })
    scene.add(mpm.object)
    mpm.emit({ center: [0, 6, 0], size: [1, 1, 1] })
    renderer.setAnimationLoop(() => { mpm.step(dt); renderer.render(scene, camera) })
    Index
    • 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.

      Parameters

      Returns MPMSolver

    buffers: MPMBuffers

    GPU buffers.

    capacity: number

    Most particles.

    count: number = 0

    Live particles (at most capacity; the oldest are overwritten when full).

    materials: string[]

    Material names compiled in, by index.

    object: Mesh<InstancedBufferGeometry, MeshBasicNodeMaterial, Object3DEventMap>

    Add this to your scene. It sits at origin; particle positions are local to it.

    options: MPMOptions

    Resolved settings.

    params: { mass: any; values: Record<string, any> }[]

    Per material: its parameters as uniforms, and particle mass in normalised units.

    particles: ParticleSystem

    The particle pool (its buffers hold position, velocity and props; it draws them).

    resolution: [number, number, number]

    Grid nodes along x, y, z.

    substeps: number = 0

    Substeps of the last MPMSolver.step.

    time: number = 0

    Simulated seconds.

    uniforms: {
        colliders: UniformNode<"int", number>;
        dt: UniformNode<"float", number>;
        dx: UniformNode<"float", number>;
        friction: UniformNode<"float", number>;
        gravity: UniformNode<"vec3", Vector3>;
        invDx: UniformNode<"float", number>;
        maxSpeed: UniformNode<"float", number>;
        shift: UniformNode<"vec3", Vector3>;
        strainScale: UniformNode<"float", number>;
        stressScale: UniformNode<"float", number>;
        walls: UniformNode<"float", number>;
    } = ...

    Shader uniforms.

    Type Declaration

    • colliders: UniformNode<"int", number>

      Colliders in use (see MPMSolver.setColliders).

    • dt: UniformNode<"float", number>

      Substep, seconds.

    • dx: UniformNode<"float", number>

      Δx.

    • friction: UniformNode<"float", number>

      Coulomb friction.

    • gravity: UniformNode<"vec3", Vector3>

      Gravity.

    • invDx: UniformNode<"float", number>

      1/Δx.

    • maxSpeed: UniformNode<"float", number>

      Speed limit.

    • shift: UniformNode<"vec3", Vector3>

      Domain move, metres (applied by the shift pass).

    • strainScale: UniformNode<"float", number>

      Colour ramp: key = 0.5 + (J − 1) × strainScale.

    • stressScale: UniformNode<"float", number>

      −dt / (2000·Δx²): P2G stress factor in normalised momentum units.

    • walls: UniformNode<"float", number>

      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.

      Parameters

      • x: number
      • y: number
      • z: number

      Returns this

    • Adds a block of particles (a seeded Δx/2 lattice in a box or sphere, or explicit world positions; see MPMEmit) with F = I, C = 0, Jp = 1. Returns how many. When the pool is full the oldest are replaced.

      Parameters

      Returns number

    • MPMSolver.step's compute passes for dt, to batch with other work in one renderer.compute([...]).

      Parameters

      • dt: number

      Returns ComputeNode[]

    • Merges input into the settings. Structural settings (see the constructor) are kept, with a warning.

      Parameters

      • input: {
            capacity?: number;
            cellSize?: number;
            cfl?: number;
            friction?: number;
            gravity?: [number, number, number];
            materials?: {
                [key: string]: { [key: string]: number | undefined } | undefined;
            };
            maxSpeed?: number;
            maxSubsteps?: number;
            origin?: [number, number, number];
            render?: {
                colors?: string[];
                opacity?: number;
                size?: number;
                strainScale?: number;
            };
            resolution?: [number, number, number];
            seed?: string | number;
            substeps?: number;
            walls?: boolean;
        }
        • Optionalcapacity?: number

          Most particles. Fixed at construction.

        • OptionalcellSize?: number

          Grid spacing Δx, metres. Particles are emitted 2 per cell per axis (8 per cell). Fixed at construction.

        • Optionalcfl?: number

          Courant number C of the stable step dt ≤ C·Δx / (maxSpeed + sound speed) (see mpmStableStep).

        • Optionalfriction?: number

          Terrain 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?: number

          Particle speed limit, m/s: the "max particle speed" of the stable step, enforced in G2P.

        • OptionalmaxSubsteps?: number

          Most 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?: number

            Opacity.

          • Optionalsize?: number

            Sprite width, in particle spacings (Δx / 2).

          • OptionalstrainScale?: number

            How 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 | number

          Seed for the emission jitter.

        • Optionalsubsteps?: number

          Substeps per frame at least. More are added when the frame is longer than the stable step allows.

        • Optionalwalls?: boolean

          Domain sides act as slip walls (else particles that leave the domain freeze).

      Returns this

    • 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).

      Parameters

      Returns this

    • 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.

      Parameters

      Returns this

    • 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.

      Parameters

      • dt: number

      Returns this