Creating Dynamic Water with Vertex Shaders in Unity

Dynamic Water Surfaces with Mesh Deformation in Unity
July 1, 2026
Realistic Ocean Waves in Unity Using Gerstner Waves
Realistic Ocean Waves in Unity Using Gerstner Waves
July 1, 2026
Dynamic Water Surfaces with Mesh Deformation in Unity
July 1, 2026
Realistic Ocean Waves in Unity Using Gerstner Waves
Realistic Ocean Waves in Unity Using Gerstner Waves
July 1, 2026

Creating Dynamic Water with Vertex Shaders in Unity

In many games, water surfaces need to look dynamic and alive. Waves, ripples, and flowing motion add realism to environments such as oceans, lakes, and rivers.

One of the most efficient ways to animate water in Unity is by using Vertex Shaders. Instead of modifying mesh vertices with C# on the CPU, vertex shaders move vertices directly on the GPU.

This approach is extremely fast and widely used in modern games.


Why Use Vertex Shaders for Water?

Updating thousands of vertices in C# every frame can be expensive. Vertex shaders solve this problem by running directly on the graphics card.

  • GPU handles the vertex calculations
  • No CPU performance cost
  • Can animate thousands of vertices efficiently
  • Perfect for large oceans or lakes

Basic Idea Behind Water Shaders

A vertex shader modifies the position of mesh vertices before they are rendered. By applying mathematical wave functions such as sine waves, we can simulate moving water.

The shader changes the Y position of vertices over time.

Wave formula example:

y = sin(x + time)


Simple Water Vertex Shader

Below is a simple shader that creates animated waves on a mesh.

Shader “Custom/SimpleWater”
{
Properties
{
_Amplitude (“Wave Height”, Float) = 0.3
_Frequency (“Wave Frequency”, Float) = 1.0
_Speed (“Wave Speed”, Float) = 1.0
_Color (“Water Color”, Color) = (0,0.5,1,1)
}

SubShader
{
Tags { “RenderType”=”Opaque” }

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

float _Amplitude;
float _Frequency;
float _Speed;
float4 _Color;

struct appdata
{
float4 vertex : POSITION;
};

struct v2f
{
float4 vertex : SV_POSITION;
};

v2f vert(appdata v)
{
v2f o;

float wave = sin(v.vertex.x * _Frequency + _Time.y * _Speed) * _Amplitude;
v.vertex.y += wave;

o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}

fixed4 frag(v2f i) : SV_Target
{
return _Color;
}

ENDCG
}
}
}


How It Works

The vertex shader modifies the height of each vertex using a sine wave function.

  • Amplitude controls the wave height
  • Frequency controls the distance between waves
  • Speed controls how fast waves move

Because this runs on the GPU, thousands of vertices can be animated with almost no performance impact.


Improving the Water Effect

To create more realistic water, developers usually combine multiple wave layers.

Example concept:


wave1 = sin(x * freq1 + time * speed1)
wave2 = sin(z * freq2 + time * speed2)

height = wave1 + wave2

Combining waves creates more natural looking water surfaces.


Performance Benefits

  • No vertex calculations on the CPU
  • Works well with large meshes
  • Scales easily to large oceans
  • Compatible with most Unity render pipelines

When Not to Use Vertex Shaders

While vertex shaders are extremely efficient, they do have limitations.

  • CPU cannot easily read the modified vertex positions
  • Physics systems cannot directly interact with shader-based waves
  • Buoyancy systems require separate wave calculations

Conclusion

Vertex shaders are one of the best techniques for creating animated water surfaces in Unity. By moving vertex calculations to the GPU, developers can achieve beautiful wave motion with minimal performance cost.

Most modern games use shader-based water for oceans, lakes, and rivers because it scales well and looks visually impressive.


 

Leave a Reply

Your email address will not be published. Required fields are marked *


Skip to toolbar