Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

FluidForces

How the air and water act on a body, worked out from the body's own surface inside every physics step: a crate floats at the depth its density gives, a long hull with its engine at the stern floats stern-down, a car driven into a lake tips as it floods and sinks, a ball falls at its terminal speed and curves with its spin, a light box is blown along by the wind, a cape streams behind a runner and a flag flutters.

Physics.onWater hears a body (with or without FluidForces) or a character going into the water and coming out, with the point and speed it crossed the surface at (a splash, a swim state), and Physics.immersion reads how much of it stands under and how deep.

On an entity holding a rigid body (Physics) the surface is the surface of the space that body's solid colliders fill together, so colliders that overlap displace the space they share once; on an entity holding a soft body (SoftBody) it is the body's surface triangles, each particle taking its share. Each step splits every triangle at the water's surface (Physics.defineWater, read at the moment the step reaches, so a floating body rides the same waves Physics.water answers and the ocean draws):

  • Under the water a part is pushed by the water's pressure at its depth. Over a closed surface that sums to the weight of the water displaced, up through the centre of what is displaced: buoyancy, with the turning it makes.
  • Every part meeting the flow is pushed back by pressure drag, 0.5 * density * drag * area * cos^2(angle) * speed^2, and dragged along by skin friction (skinDrag). The flow is the water's under its surface (current, river flow, wave motion) and the wind's above it (Physics.defineWind).
  • A part under water moving across itself near the surface makes waves that carry its motion away (waveDamping), fading with depth: what settles a floating body's bobbing and rolling within a few swings.
  • A spinning body takes a Magnus force across the flow, magnus times its spin ratio.

An open surface (a cloth, a single-sided sheet) has no inside: it takes drag on whichever face meets the flow and no buoyancy.

Public fields:

  • drag (default 1): the pressure drag coefficient of a face meeting the flow head-on. A shape takes what its faces add up to: a cube face-on reads 1, a ball about 0.5 over its cross-section.
  • skinDrag (default 0.004): friction along a face.
  • buoyancy (default 1): the factor on the water's pressure; 0 sinks the body as a stone.
  • waveDamping (default 1): the factor on that wave damping; 0 leaves a floating body bobbing on.
  • magnus (default 0): lift per unit of spin ratio; about 1 for a ball.
  • air, water (default true): which fluids act on it.
  • density (default 0): the body's density relative to the water. Above 0 the water acts on the body as on a body of that density (its pressure, its drag and the waves the body makes), so that share of its hull floats under still water whatever mass the body was given and whatever the water's density, so a heavy crate can ride high and a light one low; above 1 it sinks. 0 lets its mass and the volume of its hull decide.
  • hullSize, hullCenter (default zero): a box, full extents and centre in the body's own frame, that stands for a rigid body's surface in place of its solid colliders: an invisible float under a drawn boat, a hull that differs from what the body collides with. Zero on any axis takes the colliders.
  • waterBody (default empty): the one body of water it reads, by the name Physics.defineWater gave it (an Ocean's waterName); empty reads whichever covers each point.

A Water component places still water (a pond, a pool, a canal) and a Wind component a wind (a breeze, a fan, an updraft), each saved with its scene; Physics.defineWater / Physics.defineWind define them from a script, and an Ocean or a Terrain defines its own water. Physics.fluidForces(id) reads what the last step put on the body: buoyancy, drag, lift, force, torque, the submerged fraction and volume, the volume of its hull and its hullTriangles (0 for a rigid body with no solid collider and no hullSize, which nothing acts on), and each LiftSurface's part. A water body's density and Physics.airDensity() set how hard each fluid pushes. The peer simulating the body applies the forces; a replica moves as that peer's step moves it.

Cost: the step reads the water at each corner of the hull (a box collider's hull is 48 triangles over 26 corners; hullTriangles reads a body's) only while the hull is within its own radius of the water, and the wind at each part above it. A hull is at most 512 triangles: a mesh collider past that is simplified to fit.

-- a crate that floats in a pool whose surface stands at y = 0
local pool = entity.spawn("pool", { position = { 0, -1.5, 0 } })
pool.component.add("Water", { size = { 10, 3, 10 } })
crate.component.add("FluidForces", {})

-- a football that bends with its spin
ball.component.add("FluidForces", { magnus = 1 })

-- a flag that flutters in a gusting wind
level.component.add("Wind", { velocity = { 6, 0, 0 }, gust = 3, space = "world" })
flag.component.add("FluidForces", { water = false })