Skip to content

eulerjs API / @eulerjs/marine

@eulerjs/marine ​

Waves, buoyancy and foils: the spectral and sum-of-sines seas, Ocean and Wind, Buoyancy, sails, keels and rudders as Foils, and WaterMesh for WebGLRenderer.

Classes ​

ClassDescription
BuoyancyArchimedes' principle per cell: each cell under the surface is pushed up by the weight of the water it displaces, at its own position, so a tilted hull is pushed back upright. One instance per body: it remembers each cell's depth between steps.
FoilA wing-like surface — sail, keel, rudder — that turns the flow past it into lift (across the flow) and drag (along it). Only the part of the flow across the span counts, so a foil ignores flow along its own span.
OceanWater with a wavy surface. The water itself is still; only the surface moves.
SpectralWavesAn ocean of hundreds of thousands of waves, drawn from the JONSWAP spectrum of a wind sea and summed by inverse FFT (Tessendorf's "Simulating Ocean Water"): linear waves, sharpened at the crests by moving the surface's points sideways toward them.
SumOfSinesAn ocean surface made of peaked sinusoids (Acerola's "sum of sines" with exponential waves). Each wave's coordinates are pushed sideways by the slope of the waves before it, which sharpens crests and makes the surface move horizontally, like Gerstner waves.
SurfaceGridThe surface sampled on a horizontal grid fixed in the world, then interpolated bilinearly. Buoyancy uses it so its cost depends on the area under a hull, not on how finely the hull is voxelized. Nodes keep their grid-point offset between updates, so one inversion iteration per node is enough while the area moves slowly.
SurfaceSamplerSurface heights under a fixed set of points that move a little between calls, such as the cells of a floating hull. Each point remembers how far its undisplaced grid point was from it last time and starts from there, so a single iteration finds the displaced surface.
TablePolarA polar sampled once per degree from 0° to 180°, linearly interpolated in between.
WaterMeshRenders a SumOfSines ocean: a grid of chunks around the follow target, displaced on the GPU by exactly the waves the physics uses. The centre chunks resolve the same waves as the physics (both use waves.sampleSpacing); farther chunks drop the shortest waves from the geometry and keep them only in the per-pixel normal.
WindA steady, uniform wind.

Interfaces ​

InterfaceDescription
BuoyancyOptions-
CamberedSailOptions-
FluidMediumA fluid a foil can move through: its density and how it flows.
FoilOptions-
OceanOptions-
PolarLift and drag coefficients of a foil against its angle of attack: the angle, from 0 to π, between the foil's chord (pointing at the leading edge) and the direction the flow comes from. Past π/2 the flow arrives from the trailing edge; lift then normally changes sign.
SeaSettingsThe wind and waves a SpectralWaves is made of; see SpectralWavesOptions for each.
SeaStateThe JONSWAP spectrum of a wind sea, after Horvath's "Empirical directional wave spectra for computer graphics" (2015): how much of the sea's energy there is at each frequency, from the wind's speed and how far it has blown over open water, and how that energy spreads about the wind's direction (Mitsuyasu's cos²ˢ(θ/2), narrower near the peak). Deep water throughout.
SpectralPortWhat a Worker, a worker's own global scope and a MessagePort all are, as far as this goes.
SpectralWavesOptions-
SumOfSinesOptions-
SwellWaveOne of the swell's long waves: running along (directionX, directionZ), a unit vector.
SymmetricFoilOptions-
WaterLodLevel of detail of the water mesh: a square grid of chunks that get coarser away from the centre. Every chunk's vertex count is a multiple of one unit, so moving the whole mesh by snapStep lands every vertex back on a position some vertex had before and the triangles don't crawl while the mesh follows the camera target.
WaterLodOptions-
WaterMeshOptions-
WaveComponentOne sinusoid of the sum, as uploaded to the shader.
WavePatchThe waves of one patch: for each wavenumber on its grid, the initial amplitude h₀(k) and its partner's conjugate h₀*(-k), and how fast the wave turns, ω = √(g|k|). Zero outside the patch's band of wavenumbers.
WaveSurfaceA moving sea surface, as the physics needs it: a pure function of position and time, whose points also move sideways (so a world position's height takes finding which point of the undisturbed grid has moved there). SumOfSines and SpectralWaves are both one.
WindOptions-

Type Aliases ​

Type AliasDescription
SumOfSinesUniforms-
WaterUniforms-

Variables ​

VariableDescription
sailPolarThe sail polar of the three-sails demo, used there for both the main sail and the jib.
sumOfSinesShaderChunkGLSL that evaluates a SumOfSines exactly as SumOfSines does on the CPU. Needs the define WAVE_COUNT (= waves.waves.length) and the uniforms from createSumOfSinesUniforms.

Functions ​

FunctionDescription
camberedSailPolarA cambered sail: some lift even with the flow along the chord, rising until it stalls around 20° and then behaving like a flat plate, with drag that stays low until stall. Lift-to-drag peaks around 6, which is what lets a boat sail about 45° off the wind.
computeWaterLod-
createSumOfSinesUniformsUniform values for sumOfSinesShaderChunk. Update waveTime with updateSumOfSinesTime every frame.
directionalSpreadHow much of the energy at angular frequency ω travels at angle radians from the wind, D(ω, θ) = Q(s) |cos(θ/2)|²ˢ, with Q normalising it to 1 over every direction, and the spread s Mitsuyasu's: largest at the peak, so the longest waves keep closest to the wind.
inverseFft2dThe inverse transform, unscaled, of a size by size grid of complex values held row by row in values: v(x) = Σ_k V(k) e^(+2πi k·x / size). Every row, then every column. scratch is a buffer of the same length. Returns whichever of the two holds the result.
jonswapThe energy density at angular frequency ω, S(ω) in m²·s: integrated over ω it is the variance of the sea's height.
jonswapParametersThe spectrum's peak angular frequency and its energy scale α, from the wind and the fetch.
serveSpectralFieldsAnswers SpectralWaves' requests arriving on port: in a worker, the worker's global scope (see spectralWorkerEntry.ts), or one end of a MessageChannel to evaluate on the main thread asynchronously.
symmetricFoilPolarA symmetric foil such as a keel, rudder or centreboard: thin-airfoil lift before stall, blending into flat-plate behaviour (Cl = sin 2α, Cd = 2 sin² α) past it.
updateSumOfSinesTime-
wavenumberSpectrumThe energy density over the plane of wavenumbers, S(kx, kz) in m⁴, for waves travelling along (kx, kz) with the wind blowing toward windAngle: integrated over the plane, the sea's height variance. From S(ω) D(ω, θ) by the change of variables dω dθ = (dω/dk) / k dkx dkz, with deep water's ω = √(g k), so dω/dk = g / 2ω.

References ​

VoxelizeOptions ​

Re-exports VoxelizeOptions


Voxels ​

Re-exports Voxels

Released under the MIT License.