Unity URP · ShaderLab · HLSL · C#

URP Underwater Effects

A modular underwater rendering suite built around URP renderer features and a reusable waterline mask, with caustics, fog, refraction, volumetric light, color response, and particles.

URP Underwater Effects preview

The Goal

I wanted a reusable URP underwater effect that could distinguish the part of the camera below the waterline from the air above it, then layer multiple effects only into the underwater region.

  • Create a reliable screen-space mask for the waterline.
  • Build each visual effect as an independent URP renderer feature.
  • Allow projects to opt into only the effects they need.
  • Expose artist-tunable settings instead of baking values into shaders.
URP Underwater Effects preview
The effect stack creates a readable transition between the surface and underwater rendering while keeping the individual effects modular.

The Waterline Mask

The central technical problem is knowing which screen pixels should receive underwater effects. I built a ScriptableRendererFeature called HorizonLineTexturePass that renders the selected water-surface layer into a global _HorizonLineTexture. Other effects can sample that texture to separate underwater pixels from the air above the surface.

  • Uses a configurable layer mask to identify the waterline geometry.
  • Renders separate upper- and underside passes to build the horizon information.
  • Publishes the result globally as _HorizonLineTexture.
  • Uses temporary render targets and releases pooled command buffers after execution.
  • The horizon feature is intentionally executed before the other underwater passes.
Underwater waterline showcase
The waterline mask allows the post-process effects to remain below the surface as the camera crosses between air and water.

Modular Renderer Features

Instead of one monolithic shader, the package exposes its effects as separate URP render features. The current public project includes volumetric light rays, caustics, fog, refraction, a blurred waterline, and color changes driven by the scene's main light and ambient color. Bubbles are supplied separately as a particle prefab.

  • Volumetric light rays.
  • Animated underwater caustics.
  • Depth/atmosphere fog.
  • Screen-space refraction.
  • Blurred waterline transition.
  • Lighting-aware underwater color.
  • Bubble particle prefab.

Caustics and Lighting

The caustics renderer feature passes texture, speed, tiling, RGB split, intensity, and range settings into the underwater caustics shader. It also reads the scene's main-light transform and sends that matrix to the shader so the projected lighting can respond to the directional light rather than acting like a disconnected screen overlay.

  • Artist-controlled caustic texture, animation speed, tiling, intensity, and range.
  • Optional RGB splitting for a stylized chromatic effect.
  • Main-light orientation is supplied to the shader each render pass.
  • Implemented as a reusable ScriptableRendererFeature.
Full underwater effects showcase
The full effect stack combines the waterline, fog, caustics, refraction, lighting changes, and volumetric detail.

Extensibility

The horizon texture is also the extension point for custom effects. Additional shaders can sample _HorizonLineTexture to decide where underwater processing should occur, which lets new effects plug into the same waterline logic rather than solving that problem again.

  • Effects are independent and can be enabled selectively.
  • The shared horizon texture keeps custom extensions compatible with the existing stack.
  • A demo scene, water shader, particle assets, and prefabs are included in the repository.
  • The project is released under the MIT license.

What I Learned

  • URP renderer features can turn a one-off post effect into a reusable rendering pipeline.
  • A shared intermediate mask can simplify a whole family of related screen-space effects.
  • Temporary render targets and command-buffer lifetime need to be managed carefully.
  • Technical-art tools are stronger when artists can tune each layer independently.