Note: The implementation of this project is made with the Unreal game engine using the visual scripting language Blueprint to create the shaders for the ocean.
I’ve recently spent quite a bit of time studying various forms of water simulation within certain games. I read about the use of smooth particle hydrodynamics to achieve the water effects in Pixel Junk Shooter. The use of cellular automata to simulate water falls and large bodies of water in Mine Craft and Terraria. But I also came across an interesting interview with a developer at Ubisoft for how they simulated a dynamic ocean and buoyancy in the Assassin Creed games.
The article explains the use of Gerstner waves to achieve the shape of the ocean by forming peaks and troughs. These are then summed together to form a fractal image of the ocean. I used an article on GPU Gems to get the equations I need to implement Gerstner waves.
Using various variables the ocean can then be controlled to take on different forms. These variables include amplitude, wave length, direction, speed, steepness, phase. Within my own implementation I also included an additional variable called roughness, this value controlled the angle at which 2 waves would collide with one another. This meant that I could collide both waves into each to create a thrashing ocean, or have them both traveling in same direction for more consistent flow.
The mesh for the ocean is managed through a act of projecting a flat plane from the camera onto the surface of the ocean and then applying offset with the Gerstner Waves equation.
Left my music running by accident when filming, its the persona 3 soundtrack (awesome soundtrack), so quite frankly your welcome.
I was able to further optimise this approach by forcing vertices on the plane to cluster to the point of focus. This meant that I was able to render the entire ocean with a plane that is only 128 x 128 vertices down from a plane was 256 x 256 vertices. Meaning less Gerstner wave calculations that need to be calculated and a more efficient implementation. Below is a graph from the site Desmos that I used to devise the equations needed to create this clustering effect, and a wire frame image of the plane demonstrating vertices clustering to the point of focus.
The planes corners also have to be pushed outwards off screen as the vertices on the plane sway in all dimensions. Making it possible for the illusion of the effect to be broken. This was also done to counteract the fact that the camera updates its orientation and position after the information for the plane is sent down to the GPU. This meant I was always 1 frame behind the camera, by offsetting outwards I can mask this problem.
Below is a video demonstrating how the plane scales itself based on the view frustum of the camera, by showing what the plane actually looks like beyond the bounds of the camera.
Here is a video of the final effect, using the Ocean Manager script I can directly control the oceans form. This is done by setting up a uniform buffer object and updating this buffer whenever a variables is changed, this then in turn effects the Gerstner Wave equation being calculated in the shader.
Code for this project can be downloaded from the code listings under Ocean Simulation.