Stylized Water 2
The shader at its core is optimized through efficient use of resources and will outperform anything similar you would create using Shader Graph. Though, the “Simple” shading mode remains best suited for mobile. Water is a complex phenomenon, and requires a lot of steps to achieve a believable effect. It is arguably one of the most expensive shaders in a game, worth keeping in mind.
Modern devices can run the shader in a simple scene with all features enabled and not notice a difference. If you’re targeting older devices, be sure to disable any features that do not contribute to the art direction.
- If the scene is not using any dynamic lighting, but rather a fixed directional light and ambient color, you can disable lighting on the material to gain performance. Reflections will still work in this case, if they’re enabled.
- If the water doesn’t take up a lot of screen space, fewer pixels have to be calculated. You can possibly use this leeway to enable more features.
- Rendering the depth texture in URP essentially doubles the amount of draw calls for objects. If you assets aren’t already optimized for this, it has a negative impact. Consider disabling it in your URP asset and under the “Advanced” tab on the water material. Instead, use vertex colors to paint on foam effects.
- When having waves enabled, keep the “Count” parameter value as low as possible.
- The shader automatically takes into account if the URP is configured to use shadows and renders lights per-pixel, or per-vertex.
This involves re-rendering the scene from a mirrored perspective, so can potentially double the amount of draw calls. Shadows unfortunately cannot be disabled due to what seems to be a design flaw. For example, reflection probes always render shadows, even if they have a shadow distance of 0. This appears to be a bug.
It’s important to make use of the Culling Mask field, and only reflect layers that are important for the visual result. This would require you to create new layers, and set specific objects/prefabs to these layers.
Because a 2nd camera is used, this camera will also render using a the default renderer, which means any Render Features (eg. third-party post processing effects) will execute for this camera as well. This is wasteful, since the reflection is applied directly to the water, so any effects may appear to be applied to the reflected image twice.
To solution to this is to create a renderer, specifically for planar reflections. To do so:
In the Project window, right-click and go to Create->Rendering->Universal Render Pipeline->Forward Renderer
Next, in your pipeline asset, add the new renderer to the Renderer List (repeat this for any other pipeline asset used)
On the Planar Reflection Renderer component, configure it to use this renderer, instead of the default one
With this set up, you can ensure no unnecessary or unwanted rendering is performed for the reflections.
Because it’s common for a project to have varying quality scales, there’s a static function in place which can toggle planar reflections globally. This could be tied into something like an option in a settings menu.
You can call the static function
StylizedWater2.PlanarReflectionRenderer.SetQuality(bool allowReflections, float renderScale = -1f, float renderRange = -1f, int maxLodLevel = -1) to change settings for all active Planar Reflection Renderer instances. The last 3 parameters are optional, if left untouched these values aren’t changed.