As I am currently working on a virtual reality surfing game I needed a high-quality water shader. The problems is that existing water shaders for unity are mostly designed to work with flat water planes and not with complex three dimensional bodies of water as we see in a breaking wave. So I decided to write a new custom water surface shader from scratch:
Reflection and refraction color are both sampled from a skymap and an additional directional light. They are then blended according to the Fresnel Equation which depends on surface normal and viewing direction. The surface normals are modified by multiple combined uv map scales and offsets to simulate wave movement. Absorption in the fluid is calculated according to the Beer–Lambert law, providing separate red, green and blue absorption coefficients. This determines the perceived color of the fluid and can be adjusted to simulate the dark blue of deep ocean water or the greenish tint of shallow coastal water. The amount of absorption requires the thickness of the object, which is calculated on a per pixel basis in a separate pass by first adding up the distances of all the back-facing surfaces and then subtracting the distances of all the front-facing surfaces (Greg James, 2003). Finally, The Henyey-Greenstein phase function is used to approximate the in- and out-scattering properties in the fluid, depending on viewing- and light angle.
Tough not yet optimized, the shader performs reasonably well (~60-100 FPS in 1920x1080, 25k vertices model) on a integrated laptop graphics card. As it will be used for a surfing game were the wave is actually the main point of focus, good looking water is a key factor and is certainly worth a big chunk of the time- and performance budget.