Materials
A material is a table of numbers about a substance. Capabilities read the numbers they need; the kernel reads friction and restitution. Materials are how realism is authored: the same code makes ice slippery and rubber bounce because the data says so.
What it is for#
Every body can name a material (material: 'ice'). The host's MaterialLibrary holds the table. Use materials, not per-body hacks, for anything that is a property of stuff: density (so mass follows from shape), friction, bounce, stiffness and strength, heat capacity.
The key rule: a missing value means "does not apply"#
A material without a tensileStrength is not "weak"; it is unbreakable, because the strength capability has nothing to compare against. A material without a heat capacity does not heat. The few numbers a contact cannot do without are the exception and have library defaults:
| Property | Unit | Meaning | When missing |
|---|---|---|---|
density | kg/m³ | mass per volume | mass must be given on the body |
friction | – | static Coulomb coefficient | 0.5 |
kineticFriction | – | sliding coefficient | 0.8 × friction |
rollingFriction | – | rolling resistance: torque = coefficient × normal force × radius | 0 |
pivotFriction | – | resistance to spinning about the contact normal | 0 |
restitution | – | 0 sticks, 1 perfectly elastic | 0 |
youngModulus | Pa | stiffness | stiffness-based behaviour does not apply |
yieldStrength | Pa | where it starts to deform for good | does not yield |
tensileStrength | Pa | where it tears | does not tear |
toughness | – | energy it takes to crack | does not crack |
Other capabilities add their own keys (heat capacity, conductivity, melting point, resistivity, flammability...). Their guides list them. Any numeric key is allowed; validateMaterials checks the known ones against sane ranges.
import { MaterialLibrary, EXAMPLE_MATERIALS, validateMaterials } from '@ferret/physics';
const lib = new MaterialLibrary().load(EXAMPLE_MATERIALS);
lib.add('glass', { density: 2500, friction: 0.4, restitution: 0.6, tensileStrength: 3e7 });
const bad = validateMaterials({ plastic: { friction: 99, density: -5 } });
load throws with every problem listed when the table is invalid, so a bad level never half-loads. EXAMPLE_MATERIALS (iron, wood, stone, ice, rubber) are for examples and tests; a game defines its own.
Two materials meet#
A contact has two sides. What it uses for each property comes from, in this order:
- a pair table entry for exactly these two materials (
setPair), else - the combine rule of that property, applied to both sides' values, else
- the one value that exists, if only one side has it.
| Rule | Result | Default for |
|---|---|---|
geometric | √(a·b) | friction |
max | the larger | restitution |
mean | (a+b)/2 | rolling friction and anything else |
min | the smaller | |
multiply | a·b |
import { MaterialLibrary, EXAMPLE_MATERIALS } from '@ferret/physics';
const lib = new MaterialLibrary().load(EXAMPLE_MATERIALS);
const iceOnRubber = lib.contact('ice', 'rubber');
lib.setPair('ice', 'rubber', { friction: 0.9 }); // studded tyres on ice: not the geometric mean
const studded = lib.contact('ice', 'rubber');
Pair tables work on the light kernel. Havok does not let a game change a contact before it is solved, so it takes friction and restitution from the combine rules only; to get a different result there, change the materials themselves.
Recipes#
- A level's own materials: put them in the
physics.materialsblock of the level manifest (level block); they load with the level. - Ice, mud, rubber floors: give the floor entity a material; tune
friction. Or dial it per scope with thefrictioncapability'sscalewithout touching the material. - A bounce that fades with speed: restitution is applied above
restitutionThreshold; below it the contact is a rest. Raise the threshold for less jitter. - Mass from density: leave
massoff a body with a material that hasdensity; the kernel uses density × the shape's volume.
Debugging#
| Symptom | Cause |
|---|---|
invalid materials: … is outside … | a number out of range: units (friction is a coefficient, not a percentage) |
| A thing never breaks | its material has no tensileStrength (or the capability's own key): unbreakable by definition |
| Friction looks like the geometric mean of the two when you set a pair | you are on Havok, which does not read pair tables |
physics.materials command | prints the table the host sees right now |
Reference#
MaterialLibrary, PhysicsMaterial, CombineRule, validateMaterials, EXAMPLE_MATERIALS, DEFAULT_CONTACT.