FERRETGame engine over Babylon.js
Ferret

@ferret/physics-stretch

springs, ropes and bands that stretch and tear; cloth and soft bodies by position-based dynamics.

13 exports · source in packages/physics-stretch/src

Classes

Cloth class

class Cloth
readonly n: number
readonly x: Float64Array
readonly prev: Float64Array
readonly inv: Float64Array
readonly links: Link[]
readonly colliders: ClothCollider[]
gravity: Vec3
wind: ((p: Vec3) => Vec3) | nullwind velocity at a point
readonly def: Required<Omit<ClothDef, 'origin' | 'u' | 'v' | 'pinned' | 'tearStrain'>> & { origin: Vec3; u: Vec3; v: Vec3; tearStrain?: number }
onTear: ((l: { i: number; j: number; kind: string }) => void) | nullcalled for each link that tears, after the step
torn: numberlinks torn so far
time: number
constructor(d: ClothDef)
position(i: number): Vec3
pin(i: number)
release(i: number)
move(i: number, p: Vec3)Move a pinned particle (a hand holding a flag).
maxStrain(): numberThe largest stretch of any weave link above its rest length (0.1 = 10 %).
step(dt: number)

packages/physics-stretch/src/cloth.ts:50

SoftBody class

class SoftBody

A soft body by position-based dynamics: a closed skin of particles held by its edges and by one constraint on the volume it encloses (Müller's balloon), so a ball of jelly or a cushion squashes on the ground and bulges at the sides instead of losing its volume. Collides with planes (floor); deterministic.

readonly n: number
readonly x: Float64Array
readonly prev: Float64Array
readonly inv: number
readonly tris: number[]
readonly edges: Array<{ i: number; j: number; rest: number }>
readonly rest: number
gravity: Vec3
floors: Array<{ normal: Vec3; offset: number }>
readonly def: Required<Omit<SoftBodyDef, 'centre' | 'radius' | 'rings' | 'segments'>>
constructor(d: SoftBodyDef)
volume(): numberEnclosed volume, m³ (the divergence theorem over the skin).
centre(): Vec3
extent()Lowest point and widest extent across x, m.
step(dt: number)

packages/physics-stretch/src/soft.ts:27

Functions

makeRope function

function makeRope(kernel: PhysicsKernel, d: RopeDef): RopeResult

A chain of beads joined by links; the stiffness of the whole is E·A/L, so each of n segments is n·E·A/L.

packages/physics-stretch/src/links.ts:122

stretch function

function stretch(): StretchCapability

packages/physics-stretch/src/index.ts:30

Interfaces

ClothDef interface

interface ClothDef
nu: numberparticles along the two directions
nv: number
spacing: numberdistance between neighbouring particles, m
origin?: Vec3position of particle (0, 0), and the directions the grid runs in
u?: Vec3
v?: Vec3
mass: numbertotal mass, kg
stiffness?: number0..1: how hard the weave links are corrected each iteration
bending?: number0..1 for the bending links (0 = a flexible sheet, 1 = a stiff plate)
strainLimit?: numbera link may not be longer than its rest length times this
damping?: numbervelocity lost per second, 0..1
thickness?: numberhalf the thickness: particles stay this far outside colliders, m
friction?: number
iterations?: number
substeps?: number
pinned?: 'top' | 'corners' | 'none' | number[]particles held where they are: 'top' (the first row of v), 'corners', or indices
drag?: numberair drag coefficient, kg/s per particle against the wind
tearStrain?: numbera weave or shear link still stretched past this strain at the end of a sub-step tears (0.15 = 15 %); never when missing. The strain of the solved sheet, so it is a dial of this model: a sheet of 12 rows hangs at about 5 % under its weight

packages/physics-stretch/src/cloth.ts:14

LinkDef interface

interface LinkDef

Springs, ropes and bands between two kernel bodies. A link is a kernel spring whose rest length and stiffness this layer keeps up to date: elastic first, then plastic past the yield strain (a permanent set, with linear hardening), then broken past the tensile strain. A rope-like link does not push: when the two ends are closer than the rest length it carries no force.

a: Body
b: Body
length?: numbernatural length, m (the present distance when missing)
k?: numberstiffness N/m; or give E (Pa) and area (m²) and it is E·A/L
E?: number
area?: number
damping?: numberN·s/m
rope?: booleantrue: no force when slack
yieldStrain?: numberstrain (ΔL/L) where the link stops being elastic; never when missing
hardening?: numberplastic hardening: the yield strain grows by this ratio of the plastic strain (0 = perfectly plastic)
breakStrain?: numberstrain where the link breaks; never when missing
name?: string

packages/physics-stretch/src/links.ts:8

RopeDef interface

interface RopeDef
from: Vec3
to: Vec3
segments: number
mass: numbertotal mass, kg
E: numberstring area and Young's modulus, for the stiffness of the whole rope: k_total = E·A/L
area: number
damping?: number
anchorA?: Bodybody of the end(s): a static or kinematic body to hang from; otherwise a free end
anchorB?: Body
yieldStrain?: number
hardening?: number
breakStrain?: number
radius?: numberradius of the beads, m
rope?: boolean

packages/physics-stretch/src/links.ts:98

RopeResult interface

interface RopeResult
beads: Body[]
links: Link[]

packages/physics-stretch/src/links.ts:119

SoftBodyDef interface

interface SoftBodyDef
centre: Vec3centre and radius of the ball the body starts as
radius: number
rings?: numberrings of latitude and segments of longitude of its surface
segments?: number
mass: number
stiffness?: number0..1: how hard the skin's edges are corrected each iteration
pressure?: numberthe volume it keeps, as a share of the one it starts with (1 = a closed ball of water; above 1 = blown up)
iterations?: number
substeps?: number
damping?: numbervelocity lost per second, 0..1
friction?: number

packages/physics-stretch/src/soft.ts:3

StretchCapability interface

interface StretchCapability extends Capability
readonly links: Set<Link>
readonly cloths: Map<string, Cloth>
link(d: LinkDef): Link
rope(d: RopeDef): RopeResult
addCloth(name: string, d: ClothDef): Cloth
particles(): { asked: number; stepped: number }Particles that cloths asked for, and the part the budget lets through.

packages/physics-stretch/src/index.ts:20

Types

ClothCollider type

type ClothCollider = | { type: 'sphere'; center: Vec3; radius: number } | { type: 'plane'; normal: Vec3; offset: number } | { type: 'box'; center: Vec3; half: Vec3 } | { type: 'body'; body: Body }

Cloth and soft sheets by position-based dynamics: distance constraints along the weave and across it, bending constraints between next-but-one neighbours, a hard limit on how far any link may stretch, and collisions with spheres, planes, boxes and the bodies of the scene. Verlet integration at a fixed step with a fixed number of iterations, so a replay is identical.

packages/physics-stretch/src/cloth.ts:8

Constants

STRETCH_DEFAULTS const

const STRETCH_DEFAULTS: { particleBudget: number; wind: [number, number, number]; }

things that stretch. Links (springs, ropes, bands) are kept elastic, plastic or broken by their strain; cloth is stepped by position-based dynamics, with a particle budget so a scene cannot ask for more than it can pay.

values (each at world / level / zone / entity scope):

  particleBudget   most cloth particles stepped per frame, all cloths together   (4000)
  wind             wind velocity on cloth, [x, y, z] m/s                          ([0, 0, 0])

events: stretch:yield { link }, stretch:break { link }.

packages/physics-stretch/src/index.ts:18