Skip to content

Physics · Mechanics · core

Buoyancy

the water pushes up with the weight of what you displace

Archimedes: a body is pushed up by the weight of fluid it displaces, so it floats with ρ_object/ρ_fluid of its volume under. Boats and crates in games.

View .md
Interactive visual

The orange block drops into the cyan tank and settles. The cyan arrow is the buoyant force (it grows with how much is under water), the yellow arrow is the weight, and a green arrow appears when the floor has to hold up a block that sinks. Raise the object density above the fluid density to sink it.

What it is

Water pressure grows with depth, so the bottom of a submerged object is pushed up harder than its top is pushed down. The net upward push, the buoyant force, equals the weight of the fluid the object displaces: F_b = ρ_fluid · g · V_submerged. That is Archimedes' principle.

Compare it with the weight ρ_object · g · V. If the object is less dense than the fluid it sinks only until the displaced fluid weighs as much as it does, so it floats with a fraction ρ_object/ρ_fluid of its volume under the surface (ice: about 90%). Denser objects keep sinking until the floor supplies the missing force. Equal densities are neutrally buoyant and hover wherever they are.

Game water uses the same idea per sample point: split a hull into a few probe points, measure how deep each one is below the wave height, and push up at that point in proportion to depth. Off-centre buoyancy creates torque, which is what makes boats roll, pitch and right themselves. Add drag that scales with the submerged fraction or the object bobs forever.

Key formulas

Buoyant force
Weight
Floating fraction
Vertical motion (simulated here)

f(y) is the submerged fraction (0–1); c is water drag.

Rules of thumb

  • Densities (kg/m³): fresh water 1000, sea water ~1025, oak ~700, pine ~500, ice ~917, steel ~7850, human ~985.
  • Use 4–8 probe points on a boat hull; one point floats but never tilts.
  • Linear water drag of 1–3 s⁻¹ times the submerged fraction settles bobbing in a couple of seconds without looking syrupy.
  • Clamp per-point depth to the hull height so a deep dive does not produce unbounded lift.

Implementation

Probe-point buoyancy for a rigid body (engine-neutral):
type Vec3 = { x: number; y: number; z: number }

export function applyBuoyancy(
  body: { applyForceAtPoint(f: Vec3, p: Vec3): void; velocityAt(p: Vec3): Vec3 },
  probes: Vec3[], // world-space hull points
  waterHeight: (x: number, z: number) => number,
  volume: number, // body volume (m³)
  probeHeight: number, // vertical extent each probe represents (m)
  rhoFluid = 1000,
  g = 9.81,
  drag = 2
) {
  const share = volume / probes.length
  for (const p of probes) {
    const depth = waterHeight(p.x, p.z) - p.y
    if (depth <= 0) continue
    const f = Math.min(1, depth / probeHeight) // submerged fraction for this probe
    const v = body.velocityAt(p)
    const lift = rhoFluid * g * share * f
    const damp = rhoFluid * share * f * drag
    body.applyForceAtPoint({ x: -damp * v.x, y: lift - damp * v.y, z: -damp * v.z }, p)
  }
}

Common mistakes

  • Applying the full buoyant force as soon as an object touches the surface instead of scaling it by the submerged fraction: objects pop out of the water.
  • Pushing at the centre of mass only, so boats never roll or self-right.
  • No drag in the water, so a dropped crate bobs up and down forever.
  • Using real densities with a game mass that does not match the mesh volume: the float line ends up wrong.

Prompt

Implement buoyancy for floating crates in a TypeScript Three.js game with a fixed 1/120 s step. Inputs: crate size, density, fluid density, a waterHeight(x, z) function, gravity and water drag. Compute the submerged fraction of the box, apply F = ρ_fluid·g·V·f upward and drag proportional to f·velocity, integrate with semi-implicit Euler, and stop on the tank floor. Then extend it to 4 corner probes so the crate tilts on waves. Unit tests: a 650 kg/m³ crate in water settles with 65% of its height submerged; a 1500 kg/m³ crate ends on the floor; equal densities produce no net force when fully submerged.

Further reading

Updated 2026-11-01