Inspired by this post, I decided to try my own hand at creating a simulated ocean with Gerstner waves. After a few months of work, I managed to complete it with the help of colleagues, with the goal of releasing this publicly for anyone to use this in their games or to simply learn how it works.
Features:
Multithreaded (honestly have no idea if this is working properly)
Frustum culling
Vertex Lerping (distant vertices aren’t updated every frame)
‘Infinite’ (the ocean plane will follow your camera)
Vertex coloring / depth coloring
Texture scrolling
Accurate & performant height lookups → Buoyancy system for boats included
Zone system, allowing you to create custom zone areas with different wave parameters (ex. rough sea areas)
Whirlpools
Ocean plane can be subdivided to have more vertex detail near the camera
Shorelines (vertices are slightly transparent and colored differently near shallow water)
Synced between the server and client (can do precise height lookups on the server/client)
There are definitely improvements that can be made to the ocean, which are mentioned in the main script.
Additionally, this isn’t a perfect system, and comes with some limitations due to performance or technical reasons:
Limitations:
Height Lookup: It can rarely ‘fail’ at certain times if the vertices of the ocean mesh are very deformed, an example being a whirlpool, since the vertices are displaced in it. There are some precautions to avoid this from happening.
Ocean texture near whirlpools: The UV’s of the ocean are rotated near a whirlpool in order to mimic a vortex effect, and this obviously leads to distortion / warping around the whirlpool due to the rotating texture.
Vertex popping: Because of the way the LOD for the ocean works, vertices can occasionally ‘pop’ when the ocean plane readjusts itself to follow the camera, depending on your wave parameters. This is specifically due to the LOD having no smooth transition between different levels.
There are also some issues with EditableMeshes in general, such as vertex transparency not functioning properly unless the entire mesh plane is slightly transparent, alongside some frustum culling issues Due to this, some features may not work correctly until these issues are fixed.
There are two scripts inside StarterPlayerScripts for running the ocean, as well as multiple ModuleScripts in ReplicatedStorage. For editing the way the ocean looks, there’s a ‘Settings’ module where multiple properties of the ocean can be modified to suit your needs.
Additionally, there’s a boat, whirlpool, and rough sea area with scripts inside them to show how they’re set up.
Comments are also placed throughout most scripts / modules to help give an understanding of how it works.
How to use:
Main script is located in StarterPlayerScripts
Modules are in ReplicatedStorage (‘Gerstner’ module has a settings module nested inside)
2 boats are under Workspace, one is a boat with buoyancy simulated on the server and one is a controllable boat simulated on the client
A whirlpool and rough sea area are included to demonstrate how they are spawned in
A single part with buoyancy is also included to demonstrate height lookups for a single point / part
Workspace.Ocean is a folder where the ocean plane(s) are stored
Workspace.Map is a folder for islands required for shorelines to function
This is very impressive. Well done!
I might use this for showcases and the such.
But I do have a question. When you say “infinite” do you mean that the ocean will always be visible and nothing else is?
Could you for example, place a part and tag it with ocean which, on run transforms it into one?
You’ll need to set “DEPTH_ENABLED” to false in the settings module. This occurs because for vertex transparency to work, the entire ocean plane needs to be slightly transparent (some unintended issue that ROBLOX is working on).
Your multithreading seems to be working correctly from my testing, I tested with the BrownianMotionWaves function and 200 waves (while removing the limitation you placed on it) and was getting around 120 FPS with only one worker thread, but with 4 worker threads I was getting 200 FPS.
The client boat was programmed such that it only ‘activates’ once you sit in the VehicleSeat for it. You can easily change this to run on the client at all times, similar to how the server-sided boat works.
Yes, you can do the height lookup on the server, and it should be synced between the client and server as well.
There appears to be issues with the chunking and/or rendering priority? I notice the rough seas area for example sometimes won’t render for a while, or will influence the ocean unevenly, with some parts being effected, others having a hard cutoff, and other weird stretching issues.
Besides the rendering issues this looks great! If it was a little more polished I’d probably just straight up use this for future projects.
(It’s not letting me upload a video of it, but there’s a lot of jumping and popping in and out probably due to LOD’s, and theres noticable hard cutoffs that seem somewhat inconsistent with stuff like islands, rough sea part or the little vortex part. Like it genuinly forms a massive water wall between the rough seas area and the normal sea but based on your position will sometimes properly render and then go back to weirdness when moving your camera.)