Vixen
c7401864
csharp
public readonly ref struct WaterEvaluator

The one definition of where the surface is.

Read the guide page for this →

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? Field

    The field this reads bodies and ground from, or null for open water everywhere.

  • public WaterAttenuation Attenuation

    How the sea state falls off as the ground rises.

  • public int WaveCount

    How 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