Stylized Water 3
4.7.Reflection rendering
Reflections are a vital part of what makes water looks believable. In nature, when standing on the shoreline of a lake, most of the water’s appearance is attributed to its reflection alone.
In Unity, reflections are captured using Reflection Probes, which in turn are used for indirect lighting and reflections in glossy/metallic surfaces. The water shader is able to do the same, but this technique is never really suitable for real-time reflections, nor is it accurate enough.
Two additional methods of reflection rendering techniques are featured to resolve this.
Overview of techniques
For context, a night-time scene is used with a low camera angle, a prime scenario for reflections.
Reflection Probes
Probes capture a spherical view of the scene at their center, and store the result in a cubemap. The cubemap of the probe that’s nearest to a water surface will end up being used in the shader.
Probes should be considered a method for capturing a generalized reflection. Water is a scene looks far better with an inaccurate probe than without one at all!
Pro’s
✅ Performance efficient when baked
✅ Omni-directional, can reflect geometry behind the camera
✅ Accurately reflects the skybox 1:1
✅ Already part of a complete lighting setup (influences all materials)
Cons
❌ Not suitable for real-time reflections (eg. time of day systems)
❌ Approximates reflections. Gets less accurate the further the camera moves away from its center.
Caveats
⚠️ Best suitable for localized reflections, for instance a cave. It is difficult to capture a large environment with just a single probe.
⚠️ Updating a probe will almost always be met with a spike in CPU usage, as the process involves rendering the scene from 6 different perspectives, where each time a new render loop is being run in full. Therefore Reflection Probes need to be considered a method for static reflections
Screen-space Reflections (SSR)
This technique analyses the camera’s depth texture along a ray that travels in a water pixel’s normal direction, at regular intervals a check if performed to see if the ray hits valid geometry. If so, the color at that point is reflected back in the water. If not the reflection falls back to the Reflection Probe
Basically, a form of raytracing is employed (not RTX though)
Pro’s
✅ Real-time reflections
✅ Performance efficient (compared to Planar Reflections)
✅ Works for curved water surfaces (eg. rivers)
Cons
❌ Can only reflect geometry that is currently visible in the camera’s view (on-screen)
❌ Can be more computationally expensive than Planar Reflections (usually not!). Requires multiple depth textures samples, which can become heavy on the GPU bandwidth, especially when a lot of water pixels are on screen and running high resolutions.
Caveats
⚠️ Must be combined with reflection probes (at least one that captures the skybox)
⚠️ Transparent materials can create incorrect reflections, because they have no depth information.
⚠️ Can produce visible artifacts, such as gaps. Especially for small or thin geometry.
Planar Reflections
With planar reflections, mirror-like reflections are possible, because this technique involves re-rendered the scene from a mirrored perspective.
Reflections will be blended with reflection probes (based on the scene’s alpha channel), so you get best of both worlds. Visually, waves and normals will distort the reflection to create the illusion of a true reflection.
Pro’s
✅ Real-time reflections
✅ Highly accurate
Cons
❌ Limited to flat “planar” water surfaces only
❌ Not VR/XR compatible
❌ Computationally expensive, requires an additional render loop. Complex scenes will be stressing.
❌ Third-party fog effects often don’t support this (eg. Enviro)
Caveats
⚠️ Water objects should not be moved in height! The RecalculateBounds()
function should be called on the Planar Reflection Renderer instance if this is done.