Stylized Water Shader Documentation

Stylized Water Shader

Stylized Water Shader
Version: 2.1.6
Review

7.Troubleshooting #

(Mobile) Water turns invisible. Or depth/intersection effects disappear when running on the target device

This is solely attributed to the fact that Unity is not rendering a depth texture. The depth texture is used by the water as a way to measure its depth. Without it, the water will appear as infinitely shallow, thus turning 100% transparent!

If you’re using Forward rendering, check if your camera has the EnableDepthBuffer script attached to it. In many cases this will fix any issues.

If you aren’t using shadows anywhere in the game, Unity still strip the functionality from all shaders that enables them to write to the depth texture during the build process, because it deems it as being unused.

To get around this, create a new empty scene with a shadowed directional light. Then add a few objects to it, ensuring that any shader used in the game occurs in this scene (eg. Standard, terrain and custom shaders). Save the scene, then add it to the build list. This way, Unity will not strip the “ShadowCaster” pass from all the shaders, retaining the depth writing functionality. In the end, you don’t actually need to use this scene.

If this still doesn’t work try switching to Deferred rendering. If this does work in a build you can be sure that Unity stripped depth texture functionality from your application. What follows will be a debugging process to figure out why (consult the Frame Debugger in a development build).

This all happens outside of the scope of the water asset, and would happen to literally any water shader, so there isn’t anything it can do to affect this unfortunately.

Water depth and intersection effect do not appear (on some objects)

If you’re using Forward rendering, check if your camera has the EnableDepthBuffer script attached to it. In many cases this will fix any issues.

Objects intersecting with the water must use a shader that writes to the depth texture, otherwise there is no way to tell where it is positioned in 3D space. For instance, unlit and transparent shaders do not write to the depth texture. You can download a modified Unlit shader here, which does: https://staggart.xyz/public/Unlit_ZWrite.shader. For custom shaders, they need a “ShadowCaster” pass in order to write to the depth texture.

If using shaders other than Unlit shaders is not viable for your project, consider using vertex painting to paint the intersection effect instead.

(Mobile) When using an orthographic camera, water appears below other objects/terrain and intersection effects aren’t visible

This issue is caused by transparency sorting, mobile devices are less accurate in this manner. To rectify this, reduce the “Far clipping plane” on your camera until it starts to clip your geometry. By default this is set to 1000 units, which is overkill for orthographic scenes. Secondly, move the camera as close to the environment as possible.

These steps reduce the rendering range for the camera and therefore increase the accuracy of sorting. After which, the water should render correctly.

Intersection foam starts flickering when viewed from afar (~+1000 units)

The intersection foam effect is based on the depth texture Unity renders. On mobile platforms, this depth texture is of lower precision than on PC/Consoles. This means in the far distance, the depth value (of any given pixel) may be very close to that of the geometry behind it (eg. 0.98553 vs 0.98554). Due to floating point rounding errors, these values may appear to jitter back and forth, which translates to a visual artefact.

Solutions:

  • Limit the maximum render range by decreasing the camera’s far clipping plane value (set on the Camera component).
  • Draw the foam effect through Vertex Colors so that it is based on static data.

Fog post processing doesn’t affect the water

This is a general 3D rendering issue. Seeing as water/particle shaders are transparent, they do not write to the depth buffer. Fog is a depth-based effect, making transparent shaders virtually invisible to it. Circumventing this is not a trivial thing to do, and would at least require the water/particle shader to be modified. Unfortunately, I cannot offer such a solution as it delves more into creating a custom renderer (eg SRP).

This occurrence is barely noticed for shallow water bodies or particles close up.

Switching between perspective and orthographic camera changes water appearance

This is essentially correct, between the two camera modes, depth is rendered very differently and affects how the water is rendered. The material parameters should be configured for the camera mode you are actually using. This does mean you most likely can’t use a single material for both a perspective- and orthographic camera at the same time.

Waves aren’t high enough, even with the highest “Wave height” value

In this case, your water mesh is probably be very big. If you need higher waves than the shader value allows for, increase the scale of your mesh on the Y-axis to the same effect

Waves look very pointy, triangular

This is an indication that the vertex-density/polycount of your water mesh is too low. Add subdivisions to your mesh to increase the wave fidelity. Or consider creating a set of rectangular water mesh tiles in a grid.

Much like a pin-art toy; the more pins it has, the more detailed the shape becomes.

Transparency is set to 0, but water still has a faint bright color

This only applies to the Desktop shader. The transparency parameter doesn’t actually control the shader’s opacity, but rather controls the amount of visibility of the objects rendered underneath the water. This is known as a GrabPass. The water shader is built on the PBR model, so it inherits some shading properties such as fresnel, which explains the faint brightness.

This behaviour is by design, so it’s still possible to have crystal clear water, while retaining the refraction capabilities. Otherwise the water would simply turn invisible. When the “Unlit” toggle is checked, this is not an issue, since all lighting is overridden.

Refraction shows artifacts along edges

This is actually correct behavior, and is a common limitation of using a GrabPass. Essentially opaque objects above the water are also refracted.

A way around this is to render the geometry underneath the water into a separate refraction camera. However, the performance trade-off for such a technique is generally not worth the small visual improvement, which is why it is not implemented. It’s also something that’s can’t be toggled, based on quality settings, so would affect all users.

Water material looks black

If there is no Directional Light in your scene this may be the case. Most mobile setups do not use any lighting, for performance. In which case you should set the lighting method to “Unlit” in the Lighting tab.

Water surface flickers white and the intersection effects disappears

This is usually caused if there is no light source in the scene, or your scene-view has lighting switched off.

Objects show a pixellated white outline

This occurs when using Unity’s built-in MSAA and can be remedied by using an Anti-Aliasing image effect instead. This is because the depth texture Unity renders is created before MSAA is applied.

Surfaces looks jagged

This is due to compression of the shader textures. You can override this compression in the inspector under the “Advanced” tab.

This will impair a slightly larger memory cost as the two textures will be larger in file size.

(iOS) Black dots appear on the water

You can elevate this issue by doing taking the following steps:

  • Unset the Sun object in the Lighting tab, if set
  • Raise the Shadow Bias value on your Directional Light

`System.IO.File’ does not contain a definition for `WriteAllBytes’ error

The “WebPlayer” target platform does not support writing files to disk and is thus not supported. The WebPlayer functionality was officially deprecated since Unity 5.4.

Yes No Suggest edit
Last updated on July 4, 2023
6 of 11 users found this section helpful
Suggest Edit