Skip to content

Documentation / scene / WaterSurfaceSampler

Class: WaterSurfaceSampler

Defined in: libs/scene/src/scene/water_surface_sampler.ts:92

Height queries against a water surface, driven by the material's own evaluation of it.

Why this and not a CPU-side reconstruction of the waves: the displacement the material draws with is produced on the GPU, and any second implementation of it - re-deriving the spectrum, decoding the height textures, summing the dominant waves - is a different function that has to be kept in step by hand. Water.getSurfacePoint asks the material instead, so it is exact by construction, and it includes whatever else displaces the surface, such as a WaterInteraction field. What it costs is one point-list draw and one readback per batch, which is why queries here are batched and throttled rather than issued per call.

The queries are placed on a lattice at construction and never move. A frame asks for the same small set of positions every time, so the whole set costs one draw and one readback - the same as a single query would - and the answer is interpolated across the lattice on demand. Positions that move (a hull's own footprint, say) ride along through addExtraPoints.

The motion

The reported height eases towards the newest measurement, exponentially, and nothing else is done to it. Compensating the query lag is tempting - the measurement describes the surface a round trip before it can be used - but every attempt at it bought its smoothness back by other means: predicting from a velocity needs that velocity smoothed, extrapolating a wave diverges as the square of the distance, and rate limiting the result reintroduces the stepping it was meant to remove. A plain ease has none of those failure modes, and the lag it leaves is the lag a floating body has anyway. A rigid body should read sampleWorldYRaw instead and supply its own inertia.

Consequences a caller has to accept:

  • Resolution is the lattice spacing. A grid at h metres resolves nothing shorter than about 2 * h.
  • A probe outside the lattice is answered by the nearest cell rather than by a wrapped one; this is a window on the water, not a repeating field.
  • Nothing is known until the first batch lands; until then queries return the still-water level.

Constructors

Constructor

new WaterSurfaceSampler(water, options?): WaterSurfaceSampler

Defined in: libs/scene/src/scene/water_surface_sampler.ts:126

Creates a sampler over a body of water.

Parameters

water

WaterSurfaceSource

The water to sample.

options?

WaterSurfaceSamplerOptions = {}

Lattice and rate options.

Returns

WaterSurfaceSampler

Accessors

waveTime

Get Signature

get waveTime(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:171

Water clock of the newest accepted batch, in seconds.

Returns

number


updateHz

Get Signature

get updateHz(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:181

Upper bound on the query rate in hertz.

A ceiling, not a schedule: a batch is issued as soon as the previous one has landed if that is sooner. Raising it past what a batch costs changes nothing.

Returns

number

Set Signature

set updateHz(val): void

Defined in: libs/scene/src/scene/water_surface_sampler.ts:184

Parameters
val

number

Returns

void


timeConstant

Get Signature

get timeConstant(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:192

Seconds for the reported height to close most of the gap to a new measurement. In seconds rather than per frame so that the behaviour does not change with frame rate.

Returns

number

Set Signature

set timeConstant(val): void

Defined in: libs/scene/src/scene/water_surface_sampler.ts:195

Parameters
val

number

Returns

void


readCount

Get Signature

get readCount(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:199

Batches completed since construction.

Returns

number


failCount

Get Signature

get failCount(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:203

Batches that failed.

Returns

number


pending

Get Signature

get pending(): boolean

Defined in: libs/scene/src/scene/water_surface_sampler.ts:207

True while a batch is in flight.

Returns

boolean


pendingSeconds

Get Signature

get pendingSeconds(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:211

Seconds the batch in flight has been outstanding, or 0 when none is.

Returns

number


lastLatency

Get Signature

get lastLatency(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:215

Batch latency in seconds, as of the last one that landed.

Returns

number


batchFrames

Get Signature

get batchFrames(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:219

Frames the newest batch took to come back.

Returns

number


batchSize

Get Signature

get batchSize(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:223

Points evaluated per batch, the cost driver of this sampler.

Returns

number


ready

Get Signature

get ready(): boolean

Defined in: libs/scene/src/scene/water_surface_sampler.ts:227

True once a batch has landed and queries return surface heights.

Returns

boolean


spacing

Get Signature

get spacing(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:231

World metres between lattice samples.

Returns

number


waterLevel

Get Signature

get waterLevel(): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:235

World Y of the still-water level.

Returns

number

Methods

addExtraPoints()

addExtraPoints(inputs, onResult): () => void

Defined in: libs/scene/src/scene/water_surface_sampler.ts:251

Register world positions to evaluate alongside the lattice, every batch.

The array is held by reference and read when a batch is issued, so a caller updates the vectors in place each frame and the next batch picks them up. The listener receives the surface positions for those inputs when the batch lands, in the same order. Making these a second call to the water instead would put two feedback renders in one frame.

Parameters

inputs

Vector3[]

World positions; only X and Z are used.

onResult

(results, inputs) => void

Called per batch with the surface positions.

Returns

A function that unregisters the points.

() => void


update()

update(deltaSeconds): void

Defined in: libs/scene/src/scene/water_surface_sampler.ts:268

Advance the sampler. Call once per frame with the frame's delta.

Parameters

deltaSeconds

number

Frame delta in seconds.

Returns

void


sampleWorldY()

sampleWorldY(x, z): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:317

Surface world Y at a world XZ, eased.

Bilinear over the lattice, clamped at the edges rather than wrapped. The table this reads is advanced once a frame by update, so this is a pure lookup and can be called as often as a caller likes.

For something placed directly at the height it reads, which has no inertia of its own and needs the height to move smoothly.

Parameters

x

number

z

number

Returns

number


sampleWorldYRaw()

sampleWorldYRaw(x, z): number

Defined in: libs/scene/src/scene/water_surface_sampler.ts:327

Surface world Y at a world XZ, from the newest measurement with no easing.

For a rigid body. Feeding it the eased height adds a second lag on top of the one the query already carries, and a body a quarter second behind a falling surface is a body in the air.

Parameters

x

number

z

number

Returns

number


sampleNormal()

sampleNormal(x, z, out?): Vector3

Defined in: libs/scene/src/scene/water_surface_sampler.ts:336

Surface normal from the eased lattice, by central differences one cell apart.

Parameters

x

number

z

number

out?

Vector3

Destination, or a new vector.

Returns

Vector3

Unit normal, Y up.

Released under the MIT License.