Skip to main content

Performance

The sea is built to hold a high frame rate on ordinary clients. This page explains what costs what, so you can spend where it shows.

How it is drawn​

  • The surface near the camera is a small set of skinned EditableMesh tiles. Each vertex hangs on a bone, and the module moves bones every update; moving a bone is far cheaper than rewriting the mesh.
  • The camera sits at the corner of a 32-cell block, so only four tiles are ever animated, and the mesh never has to move when you walk: a root bone carries the re-centring.
  • Past the animated ring, one static mesh with a flat skirt runs out to RenderDistance.
  • Foam is a fine plain mesh over the inner area with a soft edge; the film is one translucent skinned mesh. Both are optional layers.
  • The wave function is Gerstner math with fixed-size arrays and no allocation in the hot loop.

Everything updates at UpdateRate (60 per second by default), not at the render rate, so a 240 fps client does no more mesh work than a 60 fps one.

What to turn​

WantTurn
The biggest single savingQuality = Fast (fewer animated vertices, no film, foam every fourth update)
Fewer updates per secondUpdateRate (30 is fine for slow seas)
Smaller animated areaInnerCells down, or CellSize up
No foamFoamStyle = None
No filmHighlights off
Flat lightingLit off draws the water unlit
A still seaStaticWaves builds the surface once and stops the clock; FlatSea removes the waves entirely

Ocean presets set sensible values for their look; Island (the default) is the balanced one.

Streaming​

When streaming loads a new area, Roblox rebuilds every skinned mesh it finds. The module keeps its meshes small and few so that rebuild stays at a few tens of milliseconds rather than a stall.

EditableMesh access​

The wave mesh is an EditableMesh, which an experience has to allow in its Experience Settings. Without it the module never builds the mesh: the sea is flat at SeaLevel for visuals and physics alike (the flat water stands in as the surface), and the Output says so once. Ocean.Waves.MeshAvailable() reports which case you are in.

Adaptive quality​

Studio has a generous EditableMesh memory budget; phones and low-end PCs do not, so a sea that builds in Studio can be refused in the live game. The renderer handles that on its own with a ladder of rungs:

RungWhat is drawn
fullEverything the settings ask for: four tiles, the horizon mesh, foam, film
no filmThe surface film is dropped
no foamFoam (and its animated image) is dropped too
one tileA single tile for the whole lattice, fewer bones
half latticeOne tile with half the cells per side
quarter latticeOne tile with a quarter of the cells per side
flatNo EditableMesh at all: a flat slab in the water's colour
  • If a build is refused, the sea drops to flat at once, so there is always water on screen, and this client's own queries (swimming, the underwater tint) follow the flat surface.
  • It then climbs from the bottom, one rung at a time, every few seconds. A refused climb keeps the current rung and doubles the wait before the next try, up to three minutes.
  • If a mesh update costs more than 7 ms for three seconds, it steps down a rung and holds off climbing for a while.

So each device settles on the best rung it can hold and keeps probing upward slowly. The rung in use is the Level attribute on the OceanSurface model, and a warning in the Output says when a build was refused. Renderer.SetLevel(n) (0 to 6) forces a rung for testing; the sea climbs back from there.

To give weak devices an easier start, set Quality to Fast and keep FoamStyle off Animated: that removes the film and the foam image before the ladder has to.

Physics side​

Heights, buoyancy and swimming use the waves the mesh can draw. A wave shorter than three of the finest cells (CellSize times the quality's scale) cannot be shown, and fades in up to six; the physics applies the same fade, so things float on the water you see. With large cells (say CellSize 32 on Fast) only the long swell remains, in the mesh and in the physics alike.

Buoyancy samples the surface at up to eight points per floating part every physics step; hundreds of floating parts are fine, thousands are not. Water events are checked once per tracked instance per frame. Obstacles, dry regions and zones are re-read twice a second, so tagging a moving ship as an obstacle costs nothing extra.

Measuring​

The Performance section shows live stats while a preview or playtest runs: frames per second, milliseconds per mesh update, animated and moved vertex counts. The OceanSurface model (under Terrain at runtime, under the Camera in a preview) carries the same numbers as attributes: UpdateMs, Animated, Bones, Tiles, Hitches, WorstMs.