Physical Ocean Surface - Developing a Realistic Water Shader

I plan to submit it to the Marketplace in a few weeks. There are some features I still want to implement for the initial release, and other features I will add later as updates.

Does the video quality of this video seem to be very bad to anyone else, or is it just on my computer?

Here is what I’m seeing on Youtube when I set it to 1080p60:

Here is a screenshot from the video I uploaded to Youtube:

What do you see on Youtube?

Youtube has some nasty compression, however i do get some better image quality than your pic (1080 on firefox). I do get something like video quality from your pic at default 480p setting, so maybe it’s not enabling you HD resolution.
You could try using Vimeo maybe, it does better job at preserving image quality than youtube.

4a6a335fd56065111d03fa64d4fb988ed335b264.jpeg

Great job btw, looks fantastic. :smiley:

He is right. Youtube is horrible. It completely compresses every video to hell.

Indeed. Never base an opinion off of the “quality” of YouTube videos. Their compression is terrible to begin with :slight_smile:

Buoyancy Update

watch?v=hMZDzfgf-n8

Implementing buoyancy for large objects was trickier than I expected, for two reasons:

First, the Gerstner equations tell us that a point A of the nominal surface shifts to the location B of the deformed surface. However, given the coordinates x and y of a point B = (x, y, z) it is not a trivial task to calculate z. It quickly became apparent that an iterative algorithm is needed to solve the problem. The algorithm tries to find a good approximation of the point A that is shifted to point B and consequently allows us to calculate z. The algorithm is implemented in blueprint and just one iteration is enough for good locking results. Even disabling the algorithm results in only a small error of the calculated wave height that may be acceptable in some cases (very large, slow moving of far away objects).

The second problem is CPU performance. Because of the large number of Gerstner waves I’m summing up in Blueprint, CPU performance can become a problem. Having a lot of floating objects, each of them evaluating the wave height at many points at 60 fps is not a good idea. Luckily, there is a lot that can be done to optimize CPU performance:

  1. Use the simple buoyancy shown in my previous video if you can get away with it. It only calculates the water displacement at one point. It works well for small, lightweight objects (floating leaf, particles etc.)
  2. It is not necessary to update the buoyancy force at each tick. A few times a second is more than enough. With this measure, the performance can be improved a lot. (Already implemented, see below)
  3. Since the motion of the water is deterministic, the motion of a passive floating object could be calculated beforehand and played back as an animation. This way, the amount of floating objects would not be limited by an expensive buoyancy calculation on the CPU.
  4. One should only calculate buoyancy for objects that are visiible. For far away objects, the simple buoyancy mode should be used.
  5. Implement the buoyancy calculations in C++ instead of blueprint (it’s on my to do list)
  6. I also noticed that CPU performance is a lot better in standalone mode than in play in editor.

So, how exactly does it work? Similar to handkors approach, I calculate the wave height at multiple points relative to the floating object. I think they way how I apply forces on the object is a bit different. I’m using a physics simulation with the following forces acting on the object:

  • gravity (UE4 physics)
  • intertia (UE4 physics)
  • buoyancy
  • damping (linear and angular, UE4 physics)
  • horizontal drag force

Each object has an array of points defined in local object space where the wave height is evaluated. This array of point locations is generated automatically, taking into account the dimensions of the object. You can set the number of points in X and Y direction on the properties of the buoyancy component. (did I mention that buoyancy is implemented in a component that you can simply add to any static mesh?)
If a point is below the water level, an upwards buoyancy force is applied at the location depending on the depth.
For performance reasons, not every point is evalueted at each tick. In the video above, each box has 9 points, and at each tick the buoyancy force of only 3 of them is updated. As you can see, the buoyancy looks fine.

If you look carefully at the video above, you can see that the boxes are also drifting horizontally. They are moving slower than the horizontal movement of the water, as if the water was gently pushing the boxes as it’s flowing around them. To achieve this effect, I calculate the relative horizontal speed of the floating object and the water surface, and apply a drag force depending on the speed difference.
Compare that to simple buoancy mode, where the floating object is locked to a spot on the water surface.

The floating boxes are not stuck on the water surface. As you can see in the video, one of the boxes slides into the water. The objects can be lifted from the water or submerged completely if you apply additional forces.

Starting at 30 seconds into the video, I display debug spheres at the locations where the wave height is evaluated and the buoyancy forces are applied. You can see some of the spheres flickering or disappearing for a fraction of a second. At these moments, the center of the sphere is above the water level, and thus no buoyancy force is applied.

These are the setting currently available on the buoyancy component:

buoyancy component.PNG

For the last few videos, 170 Gerstner waves are summed up.

Yes, I think connecting the boxes with a joint would work. The buoyancy is just a force in a normal physics simulation, you can combine it with other physics stuff.
Also, to make a ship that you can steer just add horizontal forces with an “Add Force at Location” Blueprint node.

looks amazing, how performant is that?

My GPU: AMD Radeon HD 6870
My CPU: Core i5-2500

Just to be clear, the water material of course runs completely on the GPU (incl. summing up of the Gerstner waves and the displacement calculation).

The the scene from my last video with the 2 floating boxes runs fullscreen at 37 FPS, (Frame 27.34 ms, Game 27.24 ms, Draw 1.35 ms, GPU 27.34 ms). So the reason for the low FPS is clearly the buoyancy calculation on the CPU. As I’ve written above, there is a lot of potential to speed this up, for example implementing it in C++ instead of Blueprint.

If there are no floating objects, only the GPU performance is relevant. When I remove the two boxes from the video, the scene runs fullscreen at 71 FPS (Frame 14.1 ms, Game 1.65 ms, Draw 1.49 ms, GPU 14.1 ms). So in this case the GPU is the limiting factor.

I plan to include versions of the material with a reduced number of Gerstner waves, so that you can get better performance if you need to.

I have not tried line traces. However, there is a blueprint function that will tell you the wave height at any location and time, so you can just use that.

The first thing that comes to mind is to implement the Blueprint code in C++, and have it run in parallel.

thats way too big of a difference for this feature, LIKE WAY TO BIG

Don’t get too focused on that number. I measured the FPS on the project that was used to produce the video, it has very high buoyancy quality settings. It’s not what you would do for an actual game. If I set the buoyancy component to update only 3 of the 9 points of each box per frame (instead of 6), the performance is 65 FPS. I know, the buoyancy calculation is right now too slow to support a large number of floating objects, but it’s not that bad. Also please remember that my computer is not very powerful (I posted my specs above).
Eventually this needs to be implemented in C++, it doesn’t make sense to have something performance critical implemented in Blueprint.

You should really concentrate on all those stuff, oceanic water with buoyancy (optimized, even 1 fps loss for 1 object is not acceptable), lake water, shallow water, etc.
There are no other water shaders out there besides the Epic one, as far as i can tell, so you can really become monopolist on this market.

Are C++ assets currently accepted on the Marketplace as part of a Material/Blueprint product? I would have most of the water and buoyancy logic implemented in Blueprint, and just the math in C++.

, the water looks really good… more than enough to release! About that, do you have any update when you are planning to release it? I’m either thinking of waiting for your or i will start to implement my own very similar system of gerstner waves that i have some experience with since before, but also buoyancy. Awesome job so far and probably this will forever be WIP so would be great if you could release an intermediate version asap :slight_smile:

So got a request or two as well as some questions.

Requests -

  1. Support for Shorelines
  2. Support for objects that can sink and rise. (Example: Submarine, Boats, etc. )

Question -

  1. Is made this using C++ or Blueprint? Reason why I am asking is that complex math operations can get fairly expensive performance wise in blueprint.

My plan is to submit a first version that is “good enough” in a few weeks. There are a few things that I still want to implement the release. In the meantime, I have greatly improved the performance of the buoyancy calculations. They are still done in blueprint, but now a lot more floating objects are possible at 60 fps. I will post an example soon of what is now supported. I think the buoyancy is now fast enough to be useful.
Objects that can sink and rise are already supported with the current buoyancy system. There is a public variable in the buoyancy component that controls how deep an object is submerged. Additionally, you can influence the submersion depth by adding a vertical force to an object.
I plan to implement shoreline support, but not for the first release.

Looks great, can’t help but seeing the shader/geometry interaction a bit jelly-like. Have you tried making the textures not staying at the same point on the geometry or moving them in a direction? Right now it looks like very fluid jelly because the texture gets distored and bend to much by the deforming geomety underneath. Also the movement within the bump/normal map is to static or moves in the same place rather than moving towards one direction (which would be the lower part of the deforming geometry. just my 2 cents, great work though.

PS: Maybe a noise variaton on bump strength would also help quite a bit. :slight_smile:

I am interested in purchasing this.

I’ve been working on improving the buoyancy performance to support more floating objects. It was possible to improve the performance a lot with these two optimizations:

  1. Remove all unnecessary calculations from the blueprint to make it faster. For example, the normal was always calculated even if not needed.
  2. Don’t calculate the buoyancy force for all points at each frame. Calculate the force only every few frames, and use a linear extrapolation when no force is calculated.

The linear approximation of the buoyancy force from the past frames took some time to implement and debug in Blueprint, but now it is working beautifully. For every floating object, you can specify how many points you want for evaluation of the buoyancy force, and at which frequency the force should be calculated.
This video has 48 boxes, with four test points for each box. Every other frame, the buoyancy force is calculated for one of the four test points of each box. So it takes 8 frames to update the buoyancy force on all four test points (of all boxes). At times where no buoyancy force is calculated, the force is updated according to linear extrapolation of past values.
Using these optimizations, this scene with 48 boxes runs at 60 fps on my machine.

I think the buoyancy is now fast enough for practical applications. I plan to submit the shader to the marketplace soon, my goal is to get it done in December.