Realistic ocean wave 🌊 simulation primarily based on J. Tessendorf's paper. C++ implementation using openGL and CGP library (linked as a submodule).
-
Project for the 3D-Graphics course (INF443) at Ecole Polytechnique (France).
-
Authors: Artur César Araújo Alves (czartur), Kseniia Khmelnikova (KseniaKhmelnk)
- GIF sample:
- Demo video: [link]
Everything was recorded for a 256x256 FFT resolution and 25 chunks + tesselation. We got 60 fps using a Nvidia GTX 1050 Ti.
- In root folder:
cmake -B build
cd build
make
./{root_folder_name}
- Player controls:
WASD -> (Translate) Forward/Backward/Left/Right
R/F -> (Translate) Up/Down
Q/E -> (Twist) Left/Right
SHIFT + C -> Switch cursor mode
# immersive: mouse move = camera move
# non-immersive: mouse move + left/right click = camera move
We have done so far:
- Ocean computation 🌊
- Fast Fourier Transform
- Chunk / "Tesselation"
- Fog on the horizon ☁️
- Day/Night cycle ☀️🌙
- Height based ocean color 🏔️
Possible improvements / increments:
- Foam
- Fresnel model: supports water refraction
- QuadTree / LOD: optimize ocean rendering
To proceduraly render an ocean, we generate a spectrum
As described in the paper, from this spectrum, we can calculte wave height, horizontal displacement and slope for
A simple brute force algorithm to do these calculations would lead to a quadratic complexity. Since we need to perform them in each animation frame, this would be too much expensive and that's why we need fast fourier transform: FFT gives us
A 2D FFT was implemented for
-
For each direction
$x, y, z$ , we calculate both normal and displacement maps simultaneously and independently by encoding all information in separated color channels (Red/Green for disp. && Blue/Alpha for norm.). -
Since it is a 2D-FFT, we have to perform each computation in horizontal and vertical directions.
In resume, we compute a total of 6 FFT's per frame, generating displacement and normal maps from a spectrum texture:
The procedure described above generates a single water quad. To make it infinite, we can simply arbitrarily repeat this quad, with the observation that the generating textures are perfectly tileables:
As an optimization, we use a chunk model (thanks to Guile Vieira for the idea) to render only a few of these patches (currently 25) based both on camera position and field of view:
-
We reduce the mesh resolution of patches far away from the camera since we don't need too much details there (simplistic tesselation).
-
Additionally, patches outside of the field of view are not rendered.
A "mist"(fog) effect can be achieved by attenuating the color of the fragment according to its depth. A fragment close to the camera will have a phong illumination, while a distant fragment will tend towards the color of the mist.
Day/Night cycle effect can be achieved by attenuating background color in a fragment shader according to time.
A sphere representing the sun moves accordingly to this cycle.
Ocean water is slightly more brighter at the top of the waves. We try to simulate this effect by interpolating two base water colors using height as a factor.
-
For the main ideas: J. Tessendorf's paper, Jump Trajectory's video
-
For FFT: Introduction to the Stockham FFT, General FFT's on GPU [Microsoft]
-
For Chunk: JpTanaka/Doomicraft