Andrew Walker

technical artist

Stylised Interactive Water in UE5 Pt1

, ,

This project is my attempt to build procedural, stylised water interaction in Unreal Engine 5. I was inspired by Epic’s fluid simulations and I wanted to expand on the concept by creating a system with multiple layers of interaction that rewards expressive movement. The main effect here is force propagation through a water body, captured in a render texture and used to drive flow texturing in a material. The same render texture can be sampled in additional VFX systems like foliage, debris, silt and wildlife.

Simulating Movement

Grid2D Setup in Niagara

To create interaction between the player and water body, I made an advection system in Niagara which simulates the propagation of kinetic energy through the liquid. The Grid system is a very flexible framework for achieving this, allowing us to do arbitrary math on 2D & 3D GPU buffers then writing the result to a texture for use elsewhere.
In this case, I’m using a Grid2D with a 2D vector buffer for velocity.

Adding velocity data

This module ‘draws’ new velocity information into the grid by passing location, size and intensity parameters and adding to the velocity buffer. The intensity is modulated by the speed of the object (in this case the player’s velocity).

Diffusion & Advection

To simulate the dispersal of energy, the first step is to diffuse the data by running a simple blur kernel.

Secondly, each cell of the grid samples another cell using the velocity as an offset, then averages those two velocities. A decay is applied to simulate energy loss.

Writing to a render texture

To access the simulated data in materials and other VFX systems, we need to write the Grid2D data into a Render Texture using the Niagara Data Interface.

Water Surface Material

Translucent Material vs Single-Layer Water

Unreal includes a shading model called Single Layer Water, which renders in a separate pass and uses a custom lighting model to achieve realistic results. 
For this project I chose to use a Translucent material and create the shading ‘from scratch’ so I could dial in a specific style. This approach also allows for overdrawing multiple layers in scenes where this is desired — with Single Layer Water, overlapping geometry only renders the nearest surface as a performance optimisation. 

I’m using Material Attributes to simply the graph setup when blending between different surfaces e.g. water & foam.

Surface Shading

Opacity and colour are blended with a Depth Fade, allowing for per-instance customisation. The 3-colour blend could also be replaced with a gradient for more fine-grained control.
Metallic is exposed as a parameter for artistic control.

To integrate with scene lighting, the material uses the Surface Translucency Volume for diffuse lighting. This has the drawback of not including specular reflection from light sources, which is instead faked by panning textures (ref: Mario Galaxy) and masking with the underlying scene colour.

Flow

Velocity data is stored in a texture and used to drive a flow mapping technique where a panning texture is sampled twice using different offsets. These samples are smoothly crossfaded periodically, creating the illusion of cohesive movement. 

Foam

A mask texture is also driven by flow-mapping and used to create foam in rapidly moving water. Additionally, edges are detected using depth comparison and eroded with the same mask. 

Refraction

The materials refraction mode is set to Pixel Normal Offset, which produces zero refraction at a value of 1, so we add 1 to our desired refraction scale. To maintain consistency regardless of view distance, we scale our refraction parameter with texel size.

Ripples

By getting the length of the flow vector, we can perturb the water surface with World Position Offset.
Instead of using dynamic tessellation, it is more performant to use a subdivided mesh and LODs.

Specular Reflections

Instead of taking the performance hit of forward-shading the water to get specular from all light sources (approx. 500 instructions), a panning-texture sparkle effect goes a long way to emulating the glinting of water as it reflects a light source.

From an art direction perspective, this approach sticks out in the overcast forest scene I am making. It could be turned down or masked with scene colour but I decided to add a static switch parameter so this effect can be enabled on a per-instance basis.

Next Time

Dynamic plants with GPU Ribbons, painting static flow-maps & simulating splash VFX!