Water and Liquid Shader Development for Graphics
Water is one of the most technically intensive visual effects in real-time rendering. Convincing results require simultaneous work of several systems: surface shader with Fresnel, normal map animation, foam mask, vertex displacement for waves, and properly configured underwater effect. Each of these parts affects performance, and the balance between visual quality and frame budget is the main engineering task.
Water Shader Architecture in ShaderGraph (URP)
In Universal Render Pipeline, a water shader is built in ShaderGraph on the basis of Unlit or Lit graph depending on lighting requirements. For mobile games, Unlit with fake lighting through normal map is more common — it saves several draw calls and vertex shader invocations. For PC/console — Lit with PBR parameters.
Key nodes and their function in a water shader:
Normal Map Scrolling. Two normal map texture samples with different UV tiling and different scroll directions (through Time + UV offset node). Overlay or Blend Normal node for combining them. This creates the illusion of chaotic, living surface without geometric calculations. Different scroll speeds are critical — if both textures move at the same speed, the pattern becomes obviously repeating within ~5 seconds.
Fresnel effect. Fresnel Effect node + Lerp between two water colors (deep and shallow). Fresnel Exponent in the range 2–5 for smooth transition. For URP, correctly use NDotL through Normal and View Direction nodes instead of the simplified built-in Fresnel.
Depth Fade for foam. Scene Depth node (Eye space) minus Fragment Position gives relative depth. Through Smoothstep — foam mask at the shoreline. This is one of the cheapest ways to add realistic foam, but requires Opaque Texture enabled in URP Asset (this adds an extra blit pass, worth considering).
Vertex Displacement for waves. In ShaderGraph vertex block: Sine node by UV + Time with various frequencies and amplitudes for several "wave components." Sum 2–3 waves with different Direction vectors — you get Gerstner wave approximation without full physics. Important: displacement should be moderate (0.1–0.5 units), otherwise z-fighting artefacts appear with objects on water.
HDRP Water System vs. Custom Shader
In HDRP starting with Unity 2022 LTS, there is a built-in Water System — a ready high-quality component with tessellation, caustics, underwater rendering, and foam simulation. If the project is on HDRP and not limited by platform — it makes sense to use it as a foundation and customize through Water Decal and Water Mask.
But the built-in Water System has limitations: no vertex-animated foam support (only texture), ShaderGraph customization is limited to specific Water surface shader nodes, no ability to fully override vertex shader. For stylized graphics (cartoon, stylized cel-shading), a custom shader in ShaderGraph is more flexible.
Amplify Shader Editor is an alternative to ShaderGraph for projects with legacy rendering or for teams accustomed to node-based workflow compatible with Unity 5 style. For water in Amplify, the Grab Pass node is especially convenient for refraction — in URP this requires a separate Renderer Feature, while in Amplify it is a node with parameters.
Underwater Part and Refraction
Underwater effect is a separate technical task. When the camera crosses the water plane, you need to: change post-processing (color grading + caustics + depth blur), add screen-space distortion, optionally — limit visibility with fog.
In URP, this is implemented through Custom Renderer Feature + Volume override. Shader for underwater screen distortion: Blit Material with ShaderGraph, which applies Time-based UV distortion to Blit Texture. Activated through Camera overlay plane with OnTriggerEnter/Exit, which switches Volume weights.
Water refraction in URP requires Opaque Texture enabled. On mobile platforms this is expensive — blitting the entire Opaque pass for one effect. Alternative for mobile: fake refraction through normal map with UV offset on backdrop plane, without actual grab pass.
Case Study: Water for Mobile Game
Project: mobile 3D strategy, Unity 2022 LTS, URP Mobile. Requirement: sea on game field background, 60fps on mid-range Android. Constraint: maximum 0.5ms on water shader in frame budget.
Final shader: two scrolling normal maps (256×256 px each, ASTC 6x6 compression), Fresnel on cheap NDotL approximation, foam through simple depth comparison without Opaque Texture (using Depth Texture instead — it is cheaper), vertex displacement through one Sine node with two amplitudes. No reflection — only cube map on Specular. Final frame cost: 0.3ms on Galaxy A53.
| Water Shader Type | Timeline |
|---|---|
| Basic (mobile, URP, no displacement) | 2–4 days |
| Medium (PC/console, URP Lit, with foam and Fresnel) | 4–8 days |
| High-quality (HDRP or custom with tessellation) | 1–2 weeks |
| Underwater effect + refraction | 3–5 days additional |
Cost is calculated after analyzing the platform, render pipeline, and visual references.





