Replicated water

Hi,

I’m looking for a solution for a water plane with gerstner waves that is 100% replicated. All clients must see the exact same ocean.
Any input on how to solve a problem like that?
Any good assets that is already doing it?

All help/input/ideas are greatly appreciated.

To replicate the waves, you could just synchronize the starting server time and send it to the clients to compute all the waves based on this time.

Example: server start at “Fri Dec 18 2020 16:36:57 GMT+0000”
So each client compute the time elapsed from this time (for example 14853.5468 seconds) and will get the exact same waves (considering those waves are computed procedurally according to time).
You may also synchronize time from the server so that one client is not 10s late for example.

Thank you for your answer.
That is fine for the base case
I forgot to mention that the sea also needs to be server controlled where the server is sending wave parameters to the clients.
Changes on the server needs to be the same for all clients.

Doesnt matter.
Gerstener or any wave works only off of one truly meanigful parameter. Time.
if you sync time the values you "fish"out of your cpp function (for x and y loc) will match whatever the server calculations have, since its the same math.

what you dont do, is send the computed informarion out.
in that case the game will almost always be out of sync due to lag.

So essentially, just have all the clients double-check time and meaningful parameters - amplitude and what not, or get them periodically from the server.
then pretty much everything will always be in sync. Unless someone makes a client that skims time.

We are trying to switch an old system (a simulator) to the unreal engine.
And I was told that the way they used to do it was by sending the wave spectra, then calculating the surface with an inversed fft.
Im sure that with the Unreal Engine, there are some good ways of having a sea that all parameters are controlled on the server and quickly replicated to all clients.
I will experiment with the time replication and see how far I can push that

You should use a synchronized “Network Clock”. Servers clock is authoritative, clients sync to it.

Hey Most Host, im wondering, i could do that and get the synced clock, but how would u go about making a practical example, of actually getting the water system of ue5, use this clock?, while i understand the theory, and the post u gave the link, i still wonder what do i do once i got the same time (aprox), on both the server and the clients. in short, How do i dive deep into whats generating the water algorithm and plug this new clock in. Thanks for the time.

Ha well, its a rabbit hole for sure.
I’d start with the material to check what is driving it - if you have to break into the UFS do so. It will have references to whatever is generating the algorhytm or maybe the algorhytm itself.

Either way you need to give it the correct clock to work with, or at least figure out what time it is using (game time? It is paused if game is off? What tick gropu is it in? Etc).

Some of the things are object level driven (like tick group). Some are actual values.

Best way to dive in with a search for grstner is off the engine’s git.
If that fails try amplitude, or PI2, 2pi etc.
Ofc with pi
2 you get into everything that uses a circle so the results are had to sift through.

Once you find the code, you may have to pull the source and compile from it to make changes…

Thats direct access.

Now technically you can probbaly change the clock under unreal’s nose.

GetWorld->getTimeSeconds() is a possible function to just override if it lets you…
Surely theres tutorials out there on doing this right.
If you manage to override game time, and the ocean isnt hard coded to use something else. This will likely work and sync stuff up…

I’ve synchronized the player’s time based on a post you shared in this topic. While exploring the GerstnerWaterWaves.cpp file, I noticed references to a variable named “InTime,” but I couldn’t locate its definition. Additionally, I hadn’t considered that the water timing might be derived from the material itself, as indicated by this code snippet.


inside the GetWater function i found

ClientServerTime
ClientWaterTime
ServerServerTime
ServerWaterTime

WaterTime vs ServerTime

What’s surprising is the difference in ‘GetWaterTime’ when used in blueprints inside the player controller versus the "Getservertime". It shows that the Water time is out of sync. I’m not sure if ‘GetWaterTime’ in the player controller function is identical to ‘GetWaterTime’ in the materials, but they should be the same. Therefore, resolving one issue might fix the other, achieving overall synchronization.

Do you got any ideas on how to attack it from here?.
Thanks for the time, and ive seen you in many topics, u are the man.

Exciting news, I managed to synchronize it! With your assistance, I was close to solving it but couldn’t see the solution. What I did was create a new material parameter collection and inserted my synced time, which I obtained from that post.

For anyone else trying to do the same, just replace this one:


With this one:
Solution
This is what your mpc should look like:

For the next steps, you’ll need to include a synchronized clock for all your players. You can do this by following these instructions:

Unreal Engine - A non-destructive and better synced network clock - Devtricks (vorixo.github.io)

With this, you can successfully obtain the ‘Get Server World Time’ function.

After that, simply populate the Material Parameter Collection (MPC) with the correct clock and let the magic happen.

This approach is quite inefficient, and there’s significant room for optimization. However, it serves to illustrate the concept. Note that it includes debugging prints.

Replicated water system for y’all.

1 Like

Awsome breakdown.

The “inTime” you were asking about is a function parameter.
Anything preceded with “in” usually is in the materials/.usf/material functions.

The differences in timings are not very surprising - cpp is faster than blueprint. So there is always a discordance between the 2.

I hadn’t tought of the fact that of course they use a material parameter collection… there is just so much data other than time to push on that you kind of have to.

Anyone esle attempting modifications should take care of copying said MPC and creating your own project related version - since its likely an engine file.

@Sonia_Bustos
Beware of that too. If you made modification to engine content files witout duplicating onto your project soething as simple as verifying engine files will remove all your work :wink:

Next water thing for you to try is probably going to be localized RT to bring splashes and interaction in sync.

They claimed this was something the system could do a long while back. I DOUBT it.
I suggest making your own.

Look up and learn about VectorFields. From that, FlowMaps.

From that, its simple:
Pass the player location to the water shader. Use it to place a world positon render target. Whatever happens around the player is now captured onto that render target which is then used/seen into the water.

Though you shouldnt, because its heavy in a game, you can levarage this for pretty effects like raindrops…

I suggest moving weather effects that arent shared/replicated to the normal map.
Same end result really since both pathways will end up affecting normals too. But no need to vertex displace smaller effects like this at all.

1 Like

Thank you so much for providing this solution to sync water waves rendering. It’s working on my side.

However, I have a new issue now: the buoancy system is out of sync for some reason. It must be recalculating the waves on his own and therefore not using the same “time” parameter. Do you have any idea how we could solve that issue ?

Materials and Physics are always decoupled.
One happens on the GFX. The other is needed by the CPU.

You have to modify the functions that are run by the c++ to bring in the correct time.

Unlike the material, I doubt they have a BP/Editor only entry point to this.

So, the best way to go about starting with it is to search the github repo for
Gerstner

And to see which of the result seems more plausible for the bouyancy calculations to be looking at/running.

Once you find it, injecting your own time and building from source becomes somewhat trivial - but - doing this will likely require you to compile from source any time you want to fetch an engine update…