It was a bit of a grueling all-nighter, but in the end I am quite happy with how my water is turning out! I was really inspired by two games in particular for dedicating such an effort to my game’s water: Nintendo’s The Legend of Zelda: Wind Waker and Wave Race 64! I tried to take some cues from those two examples for my own water here!
Essentially I took Unity’s Standard Assets for a base water system and edited them a ton into this really vivid water system, which also makes use of the liquid shaders included in the Retro 3D Shader available on the Unity Asset Store. To begin with, I did some browsing for the effects that looked closest to what I wanted, and then plotted out how I might combine them. Admittedly, I’m still going to be very actively working on this water, but I did want to share some of what I’ve found and learned.
The real core of this project is actually a texture that I stumbled across on Pinterest at some point and made use of for developing an equally Wind Waker-inspired water shader for Minecraft.
Essentially, I wanted to have water that was pretty much just an animated version of that texture, however I also wanted:
- a translucent fade out around the water’s edge (an effect I was able to find in Unity’s provided script ‘WaterBase’).
- ‘subdued’ reflections (which I was also able to find in Unity’s provided ‘PlanarReflection’ script).
- ‘swirling’ of the water (which is where Retro 3D shaders comes into play with its non-dithered Retro3D Liquid Shader).
For convenience’s sake here is a look at that wave-and-ripple-producing script as well. I love this implementation as it’s concise, easy-to-read, and produces outstanding results.
public class WaterWaves : MonoBehaviour
float scale = 0.2f;
float speed = 0.8f;
float noiseStrength = 1.4f;
float noiseWalk = 1f;
private Vector3 baseHeight;
Mesh mesh = GetComponent<MeshFilter>().mesh;
if (baseHeight == null)
baseHeight = mesh.vertices;
Vector3 vertices = new Vector3[baseHeight.Length];
for (int i = 0; i < vertices.Length; i++)
Vector3 vertex = baseHeight[i];
vertex.y += Mathf.Sin(Time.time * speed + baseHeight[i].x + baseHeight[i].y + baseHeight[i].z) * scale;
vertex.y += Mathf.PerlinNoise(baseHeight[i].x + noiseWalk, baseHeight[i].y + Mathf.Sin(Time.time * 0.1f)) * noiseStrength;
vertices[i] = vertex;
mesh.vertices = vertices;
I applied that script to the provided prefab for Water4Simple which I further customized to use two materials, thus two shaders: Retro3D’s Liquid ND shader (non-dithered) and Unity’s Water4 shader. I used GIMP to edit the very Wind Waker-looking texture shown above and reduce it to the “seafoam” lines which I selected in the Liquid ND shader. I also tweaked this shader’s settings to enable a very slow “swirl” effect; being enabled on a small, standing body of water I found having the swirl moving very fast looked unnatural.
Quite honestly, I spent about a solid four hours just tweaking various values in either shader, and the WaterBase script (also provided by Unity’s Standard Assets) and experimenting with including various other shaders and scripts. Even at the time of writing this I’m still essentially studying what I’ve created here because I love the end result, but I don’t fully understand what all is exactly doing what through these scripts and shaders — I’m under the impression that what I have implemented currently could be made significantly more simple!