Gerstner Waves Material doesnt work


i wanted to learn how to make a gerstner wave water shader so i followed this tutorial Mathematical Ocean for Buoyancy - YouTube

But i dont come to a result. The used mesh with the material just disappears. When i cut the connection to world displacement, the plane appears but looks also wrong.

Here the Project File

Thanks a lot!

Sound like you should have picked something a little easier to start with if you have no clue on what is wrong at all.

First of. I’ll review your formula in a sec. But of the top of my head you have an extra division by 2pi. I dont remember that being there 100%, but I also only remember the math about 20% so that’s not like saying much.

Second, forget the texture samples for the normal. The gerstner formula already gives you the masks. (Or you could even use ddy/ddx).

3rd, I cant read the divide values on the clusters. Make sure it matches the number of waves 1 to 1. 8 waves means you need to divide the result by 8 before output.
Likewise, adding the 2 clusters of 8 waves for the output means you need to divide by 2.

4th. In the image world displacement is not plugged in. The result of the divide needs to be fed into it.

Tessellation multiplier can be either 0 or 1 or more. It depends on the mesh you assign the material to, not on the material itself.

The mesh. I use a custom plane of 100m by 100m that has 8 LODs with varying degrees of vertices.
I use 250 for LOD0, 100 for LOD2.
With the tessellation multiplier of 2 you therefore get
500x500 vertices at LOD0, 400x400 at LOd1, 300, 200,100, 50,25.
The Usefulness of the multiplier is that you can reduce or increase geometry on the fly to gain some performance.

Forget the colors and everything else. Enable tessellation as PN triangles, plug it into a non translucent material, let it compile. Apply it to the mesh and test.
If it works fine you can move on to the normals. Once those work fine you then move on to coloring. After coloring you move on to enabling translucency (so you dont wait 2 days in front of the screen for shaders to compile).

Water as a fixed index of refraction (of 1.33 I think? It’s in the unreal docs). When you need to set the specular to the PBR default value as well. Also in the ue4 docs.
Likewise metallic is usually 0 (even if some unreal technical artists like to ramp the metallic value up a bit).
Roughness is generally either at 0, or it needs to be derived from the normal map by masking the Z (b channel) so that the tip of the wave is non reflective while the lower part reflects.
You may wish to multiply that mask (and clamp it 0 to 1) to increase or decrease the effect at will.

When you turn on transparency you’ll get wierd artifacts from the back faces of the wave showing before the front faces.
Either do not turn on transparency, or (if that’s not possible as it shouldn’t be in any somewhat realistic/non toon shaded project) you need to work around it by rendering the material in separate passes and filtering what appears on screen within a limited mask.
The community ocean project has some custom nodes to manage this I believe.
I ended up using the standard way of preventing outlines of the inside of a mesh from showing in my project and that works fine too.

Your parameters on the gerstner waves /instances material could be causing the displacement to be super tall and out of your field of view (as you describe the issue).
So, it may be working, you might just need to reduce the steepness to be able to see it.

Thanks for your time and your detailed answer, very appreciate that!

I tried to check-out your suggestions today and came also to the point i should do something a bit easier :smiley:
Nonetheless, i’d love to understand a few more things.

To 6th: Where can i set the varying degrees of the vertices?

I tried it also another way today (…u-with-bp.html). Looks very similar but i think it looks more like the waves are really really small (Enclosed a screenshot). So my last hope on this are the mesh settings you talked about.

And one more question depending the inputs: In my first tutorial was told to leave the inputs empty and set the check “Use Preview as Default Value”. In the way i tried today (…u-with-bp.html) There are Values on the inputs. What are the cases to use values and when its better to leave the inputs empty? Where do they get the values from then?

Thanks and kind regards!

Material functions drive the default values of the inputs.
So, when you drag and drop or otherwise add a function (like Gerstner or the cluster function) to a material, the values are set right there and then in the dialog that is created.
Scalar parameters (or any parameterized value, vector3, color, etc.) can then be changed within the Material Instance and therefore offset those predefined values.

If you leave inputs empty, you then are forced to feed manual parameters to the function. If instead you use default values, the function will just assume that’s the value you need (generally you can’t change those values though).

for 6th.
You should really create your own mesh with custom LODs

If you want to test, just do a 10m x 10m square with a vertex every 1m x 1m. Then just use the Tessellation Multiplier to have the engine generate more geometry for you.

If you are an absolute beginner getting the LODs going may be hard, so do the simple plane first, and the LODs later.

Thanks again for your effort. I had too much fun doing it to leave it at that. So i made some big steps foward and have a few more questions.

Like you can see in picture 1, the waves get cut sometimes. Maybe that are the artifacts you spoke from. How can i prevent that?. In Picture 2 you can see the backfaces of the wave.

How can i do that? You wrote also from the standard way of preventing outlines of the inside of a mesh from showing in your project. Could that be easier and how would that go?

Another Question: Whats the best way to add foam on the waves? Found the way for coast/object foam but it seems to be more difficult on the wave caps.

Thanks a lot! :slight_smile:

Waves don’t really generate foam unless they intersect.
mathematically, this could actually be masked by extracting the R and G from the single Gertner inside the cluster, and checking if the value totals to some amount around 8 (number of waves in cluster) before division.
Since the calculation is basically already there when the division occurs, it could be easy to just output that mask for usage…
another way is to simply color the tips, but in my opinion that looks too uniform, even when mixing in a randomized clouds texture in world space to prevent that.
I needed up not having so called crests.

A third way would actually be to analize the steepness value, but again, that is the result of the same math as above, the sum of 8 waves…
The issue there is that it seems too uniform when you add foam too.

Anyway, try it out. See what may work for you.

Yep, the issue you are running across is probably the blackface. Annoying.

First, throw the material in Forward Shader (also costs a little less to render I believe). In the options you should have (even with volumetric or other settings) a checkbox for rendering in a separate pass. Check that.

For filtering them out, the community ocean project as a Custom node that’s more performant then the other solution. Maybe you should just lift that. It depends on what your end goal Is, if you are putting this on the marketplace, that’s a vile idea. If it’s for personal use and publishing, that’s a great idea.

Alternatively, check out the Tom Looman series for custom depth, the culling inner triangles is a good example to start with. You just need to play around with the result, maybe making it out for distance.

Hope that helps. Looks like good progress.

Hi, of course that helps. Many thanks for this. Made a good progress with that today. The custom depth method from Looman worked really good.
The next things i try are buoyancy, water reaction with objects and a wave-height depending on the distance to the floor. It seems like especially buyoancy is heavy, so im thankful for any tips regarding this.

I just want to learn that, so it wouldn`t be good for me to use finished things :smiley:

Kind regards!

You need to create a CPP class, and set it up to be your ocean.
Within the class you run the same Gertner calculations as for the shader. (In cpp is a lot less code).
With the exact same parameters (use variables, set the variables on begin play to propagate to the material instance).
The purpose of the Gertner function on CPP will be to return the heigh at the X/Y location.

Then, assuming everything went ok and the function is blueprint callable, you can make an actor out of the props, pass the ocean as a variable, and query the height got the loc of the actor.
Then you simply replace the actor Z for a cheap hack. Or add forces for a more accurate result (paired with having the Simulate checkbox checked) to have the item move around dynamically.

The dynamic stuff is a bit harder, as you may need to create way more then 1 point to check if you should apply force up or down. The community ocean project is again a great starting spot (I don’t like the way the positioning was setup, so I ended up using sockets myself, but it’s essentially the same base idea, create test points on the fly).

As a general rule of thumb, small vessels do better with a Z replacement, but it really depends on what you need. If the intention is to have the tip raise and the bottom dip, simulation is the only way.