Water effect in Unity for Chronoloop

Water effect in Unity for Chronoloop

Making of Chronoloop Water

The water effect used in the game makes use of 3 key concepts:

  • 1: You can use a texture file to store more information by using each of the 4 channels
  • 2: Any given UVs can be altered.
  • 3: The screen also carries information.

Addressing the first concept, we can see how the following texture contains weird patterns that do not amount to a “nice” texture:

However, this is due to storing different patterns on each of the 4 possible color values: Red, Green, Blue, and Alpha. Each channel has a different pattern assigned to it:


By doing this, we can use a single texture to store up to 4 different patterns.

The second point refers to UVs, which are coordinates that all 3D objects have, which tell the graphics card “Hey I want the pixel on the texture that corresponds to these coordinates”. The coordinates always go from 0 to 1, and if a value is greater or less than those values, they loop on themselves (for example, 2.5 would loop to 0.5, and -0.3 would loop to 0.7).

If we modify the base UV coordinates, the point which is used to sample a specific pixel on the texture will change position resulting in another pixel and other possible values. This effect distorts the shown result, which we can use to our advantage to give the surface a watery look.

The third point talks about how the screen contains the information of the numerical value of each pixel’s position within it. If we use those position values as UVs, we could use them to project textures in screen space.

However, given the game’s perspective, we can use the vertical position of a pixel as depth, as we’ll see a bit later.

Chronoloop’s water effect starts from a flat plane with a huge UV matrix.

The first step is to apply a subtle displacement to the UVs and use them to sample the base texture twice, to obtain a vertical and a horizontal movement. These samples will contain the information of the red and green channels.

Both samples are then mixed and then added to the UV values so as to distort them.

The first visual layer is obtained by sampling the blue channel of the base texture, using the distorted UVs.

The result is way too uniform and the pattern is very evident, so we’ll modify it by applying a mask. This mask will be obtained by sampling the red channel of the base texture (and with unaltered UVs, which will then be resized).

This mask is then applied to the first result to obtain a much more interesting visual result.

The nest step is to obtain the sandbanks, which are stored in the texture’s alpha channel. The sandbank sampling will use distorted UVs to give them an underwater look.

To give them a slight variation, the sandbanks are sampled again; but this time with a mask applied to them (which comes from the red channel).

Both patterns are then merged into one. This resulting pattern (and the other patterns obtained for that matter) will be black and white. With that, it is very easy to assign two colors: one to black, and another to white, which gives us the following result:

By using the screen’s pixel information, knowing that a “high” pixel means that it will be located further back in the gameworld, we can obtain a mask.


With that mask we can simulate depth in the water the further back they´re located, then we substitute the sandbanks with any color.

This pattern will then receive the first obtained pattern, in order to simulate the water’s surface:

And to finish it off, we’ll reuse the “screen height” value to give the water a sheen, as if it were reflecting the sun; to obtain the final result.

By Ricardo Ibarra (Cubo)

1 Simple Game’s Technical Artist

*Download the editable file here*