public readonly ref struct WaterEvaluatorThe one definition of where the surface is.
Remarks
[35 § D2](../../docs/plan/35-water.md#d2-one-evaluator-two-hosts-and-the-seam-is-a-test), which is the decision the rest of the document hangs off. The surface height at a position is arithmetic over the field's surface channel, the Gerstner sum at that position and time attenuated by the local depth, and the ripple field's displacement where a simulation covers it. That arithmetic exists in exactly two places — here and in Raven/Library/Water/Surface.rvn — and the two are held together by a seam test with a stated tolerance of exact-to-the-float.
⚠ Why that is worth a test rather than a convention. Both references evaluate the surface twice and neither pins them together, and the symptoms are the reason people believe water is hard: a boat that hovers a hand's width above the crests in a swell, a character whose swimming state flickers at the shoreline, a buoy that sinks when the frame rate drops. Unreal ships a per-body Max Wave Height Offset to correct exactly this drift — a knob whose existence is a bug report.
Time is a water time, not a world time. Every entry point takes an explicit waterTime, and the fixed-step simulation and the render both pass a value derived from the same clock — the render interpolating within the step. A buoyancy solver reading the frame's total time and a shader reading a smoothed one is the drift, and it is invisible until the frame rate changes.
A struct over borrowed arrays, so a hundred pontoons and forty swimmers cost nothing to ask. Nothing here allocates, and the tests say so.
⚠ The Gerstner phase is evaluated at the query position rather than at the position the surface point came from, and that is a stated approximation. A Gerstner wave displaces horizontally as well as vertically, so the point that ends up above p did not start there; inverting that is a fixed-point iteration. It is not done, for the reason everything else here is done the way it is — an iteration count is a second thing the two hosts would have to keep in step, and the seam is worth more than the last few centimetres of a steep crest. The consequence is named: at high steepness a float measures the surface slightly late on the windward face of a crest, identically on both sides of the seam.
Fields and properties (3)
public WaterField? FieldThe field this reads bodies and ground from, or null for open water everywhere.
public WaterAttenuation AttenuationHow the sea state falls off as the ground rises.
public int WaveCountHow many waves the sum runs over.
Methods (6)
public WaterEvaluator(WaterField? field, ReadOnlySpan<GerstnerWave> waves, WaterAttenuation attenuation)Creates one over a field and a sea state.
public WaterSample Sample(Vector2 position, float waterTime, IWaterRipples? ripples = null)What the surface is like at a place and a time.
public float Height(Vector2 position, float waterTime, IWaterRipples? ripples = null)Where the surface is at a place and a time, and nothing else.
public void Displace(Vector2 position, float waterTime, float damping, out Vector3 offset, out Vector3 normal)The full Gerstner displacement of a point, and the surface normal there.
public float Lift(Vector2 position, float waterTime, float damping)How far up the wave sum lifts a point, without the normal.
public float Immersion(Vector2 position, float bottom, float height, float waterTime, IWaterRipples? ripples = null)How much of a capsule is under the surface, 0…1.
Used by (11)
- BuoyancyVixen.Water
- BuoyancySystemVixen.Water.Physics
- BuoyancyTestsVixen.Water.Tests
- WaterEvaluatorTestsVixen.Water.Tests
- WaterQueryVixen.Water
- WaterRippleTestsVixen.Water.Tests
- WaterSurfaceMeshVixen.Water
- WaterSurfaceMeshTestsVixen.Water.Tests
- WaterSurfaceSeamDeviceTestsVixen.Graphics.Golden.Tests
- WaterWaveTestsVixen.Water.Tests
- WaterPresenterVixen.Editor.App