New swells, spray, and whitecaps in Triton 2.78The Triton Ocean SDK has some very accurate wave models built-in already, such as JONSWAP, Pierson-Moskowitz, and Tessendorf (which is really a Phillips spectrum.) By using GPU-accelerated Fast Fourier Transforms, we’re able to simulate over 65,000 individual waves at once using physically realistic spectra for given sea states, at hundreds of frames per second.

But sometimes, you’ll have an existing wave simulation that needs to be preserved – you just want it to look better and run faster with Triton. A few of our customers have done this successfully, and here’s how they did it.

High-frequency vs. Low-frequency waves

In most cases, your existing simulation will only generate a handful of relatively low-frequency waves. These are the main “swells” that are important for accurate simulation of ship movement. But, a water surface that consists only of these larger waves looks unnatural. You need thousands of smaller, wind-generated waves added in to make your scene look good.

The strategy, then, is to allow Triton to simulate these smaller wind waves on its own, but use an external model for the larger, low frequency / high wavelength waves.

AddSwell() to the Rescue

To add in your external model’s waves, use the Triton::Environment::AddSwell() method. This method will accept a single wave of a given wave height, wavelength, direction, and phase offset. Just call this repeatedly for every wave you wish to add to our model. There’s no runtime performance cost to this at all – it basically replaces Triton’s own representation of this specific wave with your own, and processes along with everything else as part of Triton’s FFT calculation each frame.

There are a few things to note about AddSwell():

  • It takes in a wave height – this is different than the amplitude. Wave height is twice the amplitude.
  • Remember the direction and phase offset should be given in radians, not degrees.
  • If you are validating Triton’s output against your previous system, some constant phase offset may need to be added to each swell in order to correlate. In reality, it’s only the relative phase differences between waves that matter, and not the absolute positions of them, so bear that in mind.
  • Remember to use Environment::ClearSwells() if you are re-submitting a new set of swell waves.

If your external wave model specifies wave speeds or periods instead of wavelengths, you’ll need to convert them before handing them off to Triton. Wave speed may be expressed as a frequency of how often a wave crest passes a given point. Triton assumes the following relationship between this frequency (w) and wavelength (L):

Water wavelength to frequency

Triton’s results will be surprisingly accurate given its speed, but the accuracy will depend on how close of a match it can find for your wave in its existing FFT input. Also bear in mind Triton cannot simulate wavelengths higher than the size of a single tile. By default, this is 256 meters. You may increase this if necessary via the Triton.config file’s fft-grid-size and fft-grid-dimensions settings, but at a performance cost.

Triton also has a tendency to produce slightly larger swell waves than what is specified. If you find this, the setting swell-height-multiplier may be used to scale the swell waves in general.

Adding in the Capillary Waves

To have Triton fill in the gaps of all the other waves your external model didn’t simulate, just set up light wind conditions or a low sea state using Environment::SimulateSeaState() or Enviroment::AddWindFetch().

These same techniques may be used to add specific swell conditions from far-away storms to your water scene, although you may find Environment::SetDouglasSeaScale() to be an easier way to accomplish such effects.

We’ve strived to make Triton as extensible as possible for accurate simulation and training purposes, while still maintaining game-quality speed and visual effects. AddSwell() is one way we achieve that balance; we hope you find it useful!