Show / Hide Table of Contents

Water shader

Tip

The ShaderGraphEssentials_Showcase_Water scene in the Demo_URP folder showcase the scene below. Checking how it's setup is the best starting point.

Screenshot1

Depth texture

Warning

The water shader uses depth texture feature to display the dynamic foam. If you can't see the water, make sure you have activated depth texture in URP settings.

Screenshot1

Context

(time of writing, september 2019)

Almost nothing in theses water shader or script is special. You could almost do it directly yourself in classic ShaderGraph and it would have almost worked.
Let me explain. Unity's shadergraph contains a bug (or missing feature, depending on how you view it) which makes effect based on position (world position, object position, screen position, any kind of position) impossible when using the "Position" input to move vertices.
The reason is, when you move the position through the Position input and then use the position again in other parts of the graph, Unity gives you the pre-displacement position. And there are no workaround.
This bug was reported several times, an example here. I noticed it too when working on a water shader in ShaderGraph, decided to fix it and provide a water shader example as bonus value.
This fix will definitely work for anything, not only a water shader. Once you have ShaderGraph Essentials (SGE), the fix is trivial. You only have to active the Update vertex position in any SGE master node.

Screenshot1

You might ask why it's not always enabled ?
Well, one could argue that it could add a very small performance overhead. I profiled on mobile and it's unnoticeable. But because it's theorically here, I left the parameter optional.

Wave movement: CPU or GPU ?

The provided shaders support a wave movement along the up axis. It uses up to 3 sine-waves so it doesn't look repetitive and it is still reasonable performance-wise. You could definitely add more complex and realistic computations to suits your needs.

ShaderGraph Essentials provides to different shaders to move the vertices: a CPU and a GPU implementation. Using one or the other is very important choice and I am here to help you make the right one.
You don't need to be a programmer to make the correct choice for your project, but if you do have a programmer I suggest you talk to him about this.

CPU vs GPU what's the difference?

CPU is your processor, where most of your game code run. It can run highly flexible code and do a lot of different things.
GPU is your graphics card, where your shaders run. It is really fast at doing a very specific job (somewhat repetitive computations in parrallele).
Moving each water vertice is something that can be costly in performance and you have the choice to do this job on the CPU or the GPU.

On the CPU

Pros:

  • your game code can easily know the wave height at any point, and so support buoyancy (floating objects)

Cons:

  • much slower than on the GPU

On the GPU

Pros:

  • it's very fast

Cons:

  • you can't really have buoyancy (floating objects in the water)

Where can I select one or the other ?

There are both examples in the ShaderGraphEssentials_Showcase_Water scene in the Demo_LWRP folder.
Alternatively, there are two prefabs, SGE_Water_CPU and SGE_Water_GPU. Basically:

  • There are two different shader graphs: SGE_LowPolyWaterGPU and SGE_LowPolyWaterCPU
  • With the CPU version, it also needs a script to move vertices in C# code. The script is called TesselatedWater, and is meant to be put directly on the water object.
  • With the GPU version, you will tweak displacement settings directly on the material.

Settings

Screenshot1

Wave movement

If you chose the CPU version, those settings will be on the Tesselated_Water script.
If you chose the GPU version, those settings will be on the material.

Those settings are per-wave, all 3 waves are added on top of each other. What you generally want to do is have some waves with big amplitude and low speed, and some waves with lower amplitude and fast speed. This is what I've done in demo scene and it really helps breaking the sine wave repetition.

Name Type Description
Amplitude Float Height of the wave (in object space). Should be > 0.
Speed Float Speed of the wave (arbitrary units). Should be > 0.
Frequency Float Length of the wave (arbitrary units). Should be > 0.
Direction Vector2 Direction vector of the wave. Only the first 2 components matter (it corresponds to X and Z).

Depth and foam

Name Type Description
Depth size Float In meters, represent the Ocean max depth. It doesn't directly impact visuals, but is used so all other parameters are relative (in %) instead of absolute.
For this reason, I suggest that you enter a value here early on, then left it untouched. Because a lot of parameters depend on this one, you will have to re-tweak everything after touching the depth size.
Foam Color Color Color of the foam.
Foam Opacity Float Opacity of the foam, between 0 and 1.
Foam Size Float How big is the foam (relative to depth size).
Foam Strength Float Multiplier on the final foam color. A very high value will start to remove the foam fade-out near objects.

Color

Name Type Description
Shallow Water Color Color of the water near objects.
Deep water Color Color of the water far from objects.
Color Fade Begin Float How close to the shore will the color begin to fade from Shallow to Deep water color. Should be inferior to Color fade end.
Color Fade End Float How close to the shore will the color end to fade from Shallow to Deep water color. Should be superior to Color fade begin.

Alpha

Name Type Description
Alpha Float Overall opacity of the water.
Alpha Depth Fade Float Allow the water to smoothly fade when close to objects (based on depth texture). A value of 0 means no fade.

Lighting

The water shader is based on the SGE SimpleLit master node. If you would need to change it to a PBR master node, please contact me.

Name Type Description
Smoothness Float Define how the specular will look like.
Specular color Float Color and intensity of specular highlights.
Normal strength Float Specific to the GPU implementation. Required because with the GPU normals are computed in the pixel shader.
  • Improve this Doc
Back to top Copyright Pierre-Henri BARRALIS 2019