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.
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.
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.
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
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. |