@ferret/waves
Waves on open water, in the style of @ferret/clouds: a pure field of position, time and the wind, the same on every peer, no Babylon.
The picture stays buildWater of @ferret/levels (Gerstner wav…
Waves on open water, in the style of @ferret/clouds: a pure field of position, time and the wind, the same on every peer, no Babylon.
The picture stays buildWater of @ferret/levels (Gerstner waves in the vertex shader, which Unreal's Water plugin also feeds); this
package gives it what it lacks: a sea state made from the wind (seaState returns the WaterWave[] a WaterDef takes), the height of
the surface where a ship floats (the shader moves points sideways too, so the height at a world point is found by undoing that move),
the slope, the speed of the water, and where the crests break into foam.
Classes
SeaFromFlow class
class SeaFromFlowA sea that follows the wind of a @ferret/flow field. update(t) reads the wind and returns a new list of waves when the wind has changed enough (a front arrives, a storm builds) and null while the sea stays as it is; hand the list to WaterSurfaceView.setWaves. The result is a pure function of the field and the time, so every peer that updates with the same times gets the same sea. The wave phases jump when the list changes, so keep the steps large rather than small.
waves: Wave[] | |
constructor(private field: FlowField, o: SeaFromFlowOptions = {}) | |
wind(t: number): { speed: number; dir: number } | the wind now: speed m/s and the direction the waves go, degrees (0 = +x) |
update(t: number): Wave[] | null |
packages/waves/src/index.ts:138
Wake class
class WakeThe trail of ships on the water: white water that spreads and fades behind each hull. A ship calls add every frame with its position, speed and beam; foam(x, z, t) reads 0..1 for the picture. The trail widens at the Kelvin angle (about 19.5 degrees) and fades over life seconds. A pure function of what was added, so peers that add the same samples see the same wake. push also stirs a WaterSurface of
constructor(private o: { life?: number; spacing?: number; max?: number } = {}) | |
get life(): number | |
add(x: number, z: number, t: number, speed: number, width = 4): void | a hull at (x, z) moving at speed m/s, width m across; samples closer than spacing m to the last are dropped |
prune(t: number): void | drop what has faded; call now and then |
get samples(): number | |
foam(x: number, z: number, t: number): number | white water at a point, 0..1 |
push(surface: { disturb(x: number, z: number, volume: number, radius?: number): void }, x: number, z: number, speed: number, width: number, dt: number): void | push the hull's displacement into a harbour surface: the volume a hull of this size moving at speed sweeps aside in dt seconds |
packages/waves/src/index.ts:177
WaveField class
class WaveFieldconstructor(waves: Wave[]) | |
get waves(): number | |
displacement(x: number, z: number, t: number): V3 | the move of the rest point (x, z) at time t: sideways (x, z) and up (y), as the shader of buildWater does it |
height(x: number, z: number, t: number): number | the height of the surface above the rest level over the world point (x, z): the rest point whose move lands there is found first |
normal(x: number, z: number, t: number): V3 | the unit normal of the surface at the rest point (x, z) |
velocity(x: number, z: number, t: number): V3 | the velocity of the water particles at the surface (orbital motion), m/s: what carries a floating thing and rocks a boat |
foam(x: number, z: number, t: number): number | How much the crest breaks here, 0 (smooth) .. 1 (white water): the Jacobian of the sideways move is 1 on a calm surface and falls towards zero where the water piles up; foam comes where it falls below about 0.6. |
packages/waves/src/index.ts:56
Functions
seaScale function
function seaScale(wind: number): { peak: number; hs: number }The peak wavelength (m) and the significant wave height (m) of a fully developed sea at a wind speed (m/s): Pierson-Moskowitz.
packages/waves/src/index.ts:26
seaState function
function seaState(wind: number, windDir = 0, o: SeaOptions = {}): Wave[]The waves of a sea driven by a wind of wind m/s from the direction windDir (degrees, 0 = +x: where the waves go). The components are
sampled from the Pierson-Moskowitz spectrum, log-spaced from short chop to the long waves, each with the amplitude the spectrum gives it
and a direction spread around the wind; the result is a deterministic function of its arguments. Calm wind gives a flat sea.
packages/waves/src/index.ts:36
surfaceFn function
function surfaceFn(field: WaveField, level = 0, local?: { height(x: number, z: number): number; level?: number }): (x: number, z: number, t: number) => numberThe height function a ship rides (Environment.surface of
packages/waves/src/index.ts:165
Interfaces
SeaFromFlowOptions interface
interface SeaFromFlowOptions extends SeaOptionsat?: [number, number] | where (x, z) the wind is read: the middle of the water |
height?: number | height of the reading above the surface, m (the standard 10 m wind) |
speedStep?: number | the sea is made again only when the wind has changed this much: m/s ... |
turnStep?: number | ... or turned this much, degrees. A real sea answers a changing wind slowly, so small changes leave it as it is. |
packages/waves/src/index.ts:121
SeaOptions interface
interface SeaOptionscount?: number | how many wave components (the shader takes up to 16) |
seed?: number | |
spread?: number | how widely the waves spread around the wind, degrees either side (a young sea is wide, a swell narrow) |
sharpness?: number | 0..1 how sharp the crests are; the sum is held below the point where a crest loops over |
packages/waves/src/index.ts:15
Wave interface
interface Wavethe same shape as WaterWave of
wavelength: number | |
amplitude: number | |
steepness?: number | |
direction?: number |
packages/waves/src/index.ts:10
Types
V3 type
type V3 = [number, number, number]Waves on open water, in the style of
packages/waves/src/index.ts:8