Hi again, apologies for the 1 year bump.
![]()
After a long hiatus of essentially forgetting about this project and losing motivation, it has returned, and better than ever.
=== Technical Breakdown ===
Basically the entire architecture has changed while following the same core rules:
- Optimized
- Customizable
- OPEN-SOURCE (soon)
The changes are quite drastic. Here’s a vague summary:
- Moved from Gerstner to JONSWAP FFT
- Proper foam buffer
- Approximated camera-based Subsurface Scattering
- Animated normal map
- Higher-res meshes (customizable)
- Clean, seamless tiling
- Server & Client replication
- BUOYANCY.
=== Showcase ===
Clearly, there's a lot to explain so why don't I just show you?
SORRY IN ADVANCE FOR CHOPPY RECORDINGS, THAT IS JUST MY SLOW COMPUTER <3
You can get choppier, foamy waves with different colors:
Or even larger, rolling swells:
Ah, and how could I forget about our (pseudo)buoyancy?
Pretty much every single little detail is customizable and not super hacky unlike previous Gerstner wave attempts.
=== Performance/Benchmarking ===
Now I really have no clue how to benchmark but here are some results on my device (AMD Ryzen 5 7520U CPU + AMD Radeon 610M iGPU).
Do note that GPU times here are essentially irrelevant as our entire script runs entirely on the CPU, so I won’t be measuring those metrics.
Worst-case (64x64 resolution):
Ocean takes up avg. ~9ms of CPU timeGood-case (32x32 resolution):
Ocean takes up avg. ~2ms of CPU time.Lower resolutions are sub-1ms and won’t be measured.
What I found interesting was the bottleneck isn’t actually the FFT itself but rather the enormous number of SetPosition() or SetColor() calls we’re sending. Having a bulk API for these operations would increase performance significantly and unlock further visual improvements.
That’s why I’ve made a feature request for exactly that so go check it out if you so wish.
Well anyhow, that’s about it. If you’ve got any questions or feedback feel free to lay it out.
Got any suggestions or ways to improve it? Tell me!
Thanks for reading. ![]()

