Wind Waker 2d Water Shader (GODOT 4)

I did not create this shader, i just changed it so it can be used in Godot 4. I also modified to take care of the camera zoom and position without script. The original is found here

Shader code
shader_type canvas_item;


uniform vec4 WATER_COL : source_color =  vec4(0.176471, 0.635294, 0.85098, 1.0);
uniform vec4 WATER2_COL : source_color =  vec4(0.0588235, 0.529412, 0.776471, 1.0);
uniform vec4 FOAM_COL : source_color = vec4(0.87451, 0.988235, 1, 1.0);

uniform float distortion_speed = 2.0;
uniform vec2 tile = vec2(5.0, 5.0);
uniform vec2 offset = vec2(0, 0);

const float TWOPI = 6.283185307;
const float SIXPI = 18.84955592;


float circ(vec2 pos, vec2 c, float s)
{
    c = abs(pos - c);
    c = min(c, 1.0 - c);

    return smoothstep(0.0, 0.002, sqrt(s) - sqrt(dot(c, c))) * -1.0;
}


float waterlayer(vec2 uv)
{
    uv = mod(uv, 1.0); // Clamp to [0..1]
    float ret = 1.0;
    ret += circ(uv, vec2(0.37378, 0.277169), 0.0268181);
    ret += circ(uv, vec2(0.0317477, 0.540372), 0.0193742);
    ret += circ(uv, vec2(0.430044, 0.882218), 0.0232337);
    ret += circ(uv, vec2(0.641033, 0.695106), 0.0117864);
    ret += circ(uv, vec2(0.0146398, 0.0791346), 0.0299458);
    ret += circ(uv, vec2(0.43871, 0.394445), 0.0289087);
    ret += circ(uv, vec2(0.909446, 0.878141), 0.028466);
    ret += circ(uv, vec2(0.310149, 0.686637), 0.0128496);
    ret += circ(uv, vec2(0.928617, 0.195986), 0.0152041);
    ret += circ(uv, vec2(0.0438506, 0.868153), 0.0268601);
    ret += circ(uv, vec2(0.308619, 0.194937), 0.00806102);
    ret += circ(uv, vec2(0.349922, 0.449714), 0.00928667);
    ret += circ(uv, vec2(0.0449556, 0.953415), 0.023126);
    ret += circ(uv, vec2(0.117761, 0.503309), 0.0151272);
    ret += circ(uv, vec2(0.563517, 0.244991), 0.0292322);
    ret += circ(uv, vec2(0.566936, 0.954457), 0.00981141);
    ret += circ(uv, vec2(0.0489944, 0.200931), 0.0178746);
    ret += circ(uv, vec2(0.569297, 0.624893), 0.0132408);
    ret += circ(uv, vec2(0.298347, 0.710972), 0.0114426);
    ret += circ(uv, vec2(0.878141, 0.771279), 0.00322719);
    ret += circ(uv, vec2(0.150995, 0.376221), 0.00216157);
    ret += circ(uv, vec2(0.119673, 0.541984), 0.0124621);
    ret += circ(uv, vec2(0.629598, 0.295629), 0.0198736);
    ret += circ(uv, vec2(0.334357, 0.266278), 0.0187145);
    ret += circ(uv, vec2(0.918044, 0.968163), 0.0182928);
    ret += circ(uv, vec2(0.965445, 0.505026), 0.006348);
    ret += circ(uv, vec2(0.514847, 0.865444), 0.00623523);
    ret += circ(uv, vec2(0.710575, 0.0415131), 0.00322689);
    ret += circ(uv, vec2(0.71403, 0.576945), 0.0215641);
    ret += circ(uv, vec2(0.748873, 0.413325), 0.0110795);
    ret += circ(uv, vec2(0.0623365, 0.896713), 0.0236203);
    ret += circ(uv, vec2(0.980482, 0.473849), 0.00573439);
    ret += circ(uv, vec2(0.647463, 0.654349), 0.0188713);
    ret += circ(uv, vec2(0.651406, 0.981297), 0.00710875);
    ret += circ(uv, vec2(0.428928, 0.382426), 0.0298806);
    ret += circ(uv, vec2(0.811545, 0.62568), 0.00265539);
    ret += circ(uv, vec2(0.400787, 0.74162), 0.00486609);
    ret += circ(uv, vec2(0.331283, 0.418536), 0.00598028);
    ret += circ(uv, vec2(0.894762, 0.0657997), 0.00760375);
    ret += circ(uv, vec2(0.525104, 0.572233), 0.0141796);
    ret += circ(uv, vec2(0.431526, 0.911372), 0.0213234);
    ret += circ(uv, vec2(0.658212, 0.910553), 0.000741023);
    ret += circ(uv, vec2(0.514523, 0.243263), 0.0270685);
    ret += circ(uv, vec2(0.0249494, 0.252872), 0.00876653);
    ret += circ(uv, vec2(0.502214, 0.47269), 0.0234534);
    ret += circ(uv, vec2(0.693271, 0.431469), 0.0246533);
    ret += circ(uv, vec2(0.415, 0.884418), 0.0271696);
    ret += circ(uv, vec2(0.149073, 0.41204), 0.00497198);
    ret += circ(uv, vec2(0.533816, 0.897634), 0.00650833);
    ret += circ(uv, vec2(0.0409132, 0.83406), 0.0191398);
    ret += circ(uv, vec2(0.638585, 0.646019), 0.0206129);
    ret += circ(uv, vec2(0.660342, 0.966541), 0.0053511);
    ret += circ(uv, vec2(0.513783, 0.142233), 0.00471653);
    ret += circ(uv, vec2(0.124305, 0.644263), 0.00116724);
    ret += circ(uv, vec2(0.99871, 0.583864), 0.0107329);
    ret += circ(uv, vec2(0.894879, 0.233289), 0.00667092);
    ret += circ(uv, vec2(0.246286, 0.682766), 0.00411623);
    ret += circ(uv, vec2(0.0761895, 0.16327), 0.0145935);
    ret += circ(uv, vec2(0.949386, 0.802936), 0.0100873);
    ret += circ(uv, vec2(0.480122, 0.196554), 0.0110185);
    ret += circ(uv, vec2(0.896854, 0.803707), 0.013969);
    ret += circ(uv, vec2(0.292865, 0.762973), 0.00566413);
    ret += circ(uv, vec2(0.0995585, 0.117457), 0.00869407);
    ret += circ(uv, vec2(0.377713, 0.00335442), 0.0063147);
    ret += circ(uv, vec2(0.506365, 0.531118), 0.0144016);
    ret += circ(uv, vec2(0.408806, 0.894771), 0.0243923);
    ret += circ(uv, vec2(0.143579, 0.85138), 0.00418529);
    ret += circ(uv, vec2(0.0902811, 0.181775), 0.0108896);
    ret += circ(uv, vec2(0.780695, 0.394644), 0.00475475);
    ret += circ(uv, vec2(0.298036, 0.625531), 0.00325285);
    ret += circ(uv, vec2(0.218423, 0.714537), 0.00157212);
    ret += circ(uv, vec2(0.658836, 0.159556), 0.00225897);
    ret += circ(uv, vec2(0.987324, 0.146545), 0.0288391);
    ret += circ(uv, vec2(0.222646, 0.251694), 0.00092276);
    ret += circ(uv, vec2(0.159826, 0.528063), 0.00605293);
	return max(ret, 0.0);
}

vec3 water(vec2 uv, vec3 cdir, float iTime)
{
    uv *= vec2(0.25);
	
	

    // Parallax height distortion with two directional waves at
    // slightly different angles.
    vec2 a = 0.025 * cdir.xz / cdir.y; // Parallax offset
    float h = sin(uv.x + iTime); // Height at UV
    uv += a * h;
    h = sin(0.841471 * uv.x - 0.540302 * uv.y + iTime);
    uv += a * h;
    
    // Texture distortion
    float d1 = mod(uv.x + uv.y, TWOPI);
    float d2 = mod((uv.x + uv.y + 0.25) * 1.3, SIXPI);
    d1 = iTime * 0.07 + d1;
    d2 = iTime * 0.5 + d2;
    vec2 dist = vec2(
    	sin(d1) * 0.15 + sin(d2) * 0.05,
    	cos(d1) * 0.15 + cos(d2) * 0.05
    );
    
    vec3 ret = mix(WATER_COL.rgb, WATER2_COL.rgb, waterlayer(uv + dist.xy));
    ret = mix(ret, FOAM_COL.rgb, waterlayer(vec2(1.0) - uv - dist.yx));
    return ret;
}

varying vec2 globalposition;
void vertex(){
	globalposition = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}

void fragment() {
	vec2 uv = globalposition / 32.0;
	COLOR.rgb = vec3(water(uv * tile + offset, vec3(0,1,0), TIME * distortion_speed));
}
Tags
Godot4;Water;2D
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from zeludtnecniv

2D Water distortion effect (Godot 4)

Related shaders

Wind Waker 2d Water Shader Canvas_Item

Tilemap Wind shader

Topdown wind shader

Subscribe
Notify of
guest

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Nate
Nate
9 months ago

I can’t get this one to work… it shows up just fine in the material when I’m looking at it, but if I try and set the material to a plane it doesn’t do anything.

afreytes
9 months ago
Reply to  Nate

I implemented this a few weeks ago on a 3D Scene. Here’s what I did:

Add new Spatial scene with a Node3D root (or you can add to a current spatial scene the following steps).Add new MeshInstance3D.On the MeshInstance3D, add a new mesh, and choose New Plane Mesh.On the Plane Mesh, add a new Material and choose New Shader Material.On Material, click on Shader to edit the code. Copy the code on this page in the Saader Editor window.On the Main Menu, click Save All.Here’s how it looks in my scene: https://mastodon.gamedev.place/@afreytes/110690282182206013

I’m still learning Godot myself, but come join other fellow game devs in the https://mastodon.gamedev.place server.

PS: Make sure to look at the mesh from all angles, just in case the mesh was facing the wrong direction!

Last edited 9 months ago by afreytes
baiteryamato
baiteryamato
2 months ago
Reply to  afreytes

not working, only gray material

baiteryamato
baiteryamato
2 months ago

For those on Godot 4, here’s the updated version of the code for instance 3D(spatial) (Tested on 4.2.1)

shader_type spatial;

uniform vec4 WATER_COL : source_color = vec4(0.04, 0.38, 0.88, 1.0);
uniform vec4 WATER2_COL : source_color = vec4(0.04, 0.35, 0.78, 1.0);
uniform vec4 FOAM_COL : source_color = vec4(0.8125, 0.9609, 0.9648, 1.0);

uniform float distortion_speed = 2.0;
uniform vec2 tile = vec2(5.0, 5.0);
uniform float wave_speed = 1.5;

const float TWOPI = 6.283185307;
const float SIXPI = 18.84955592;

float circ(vec2 pos, vec2 c, float s)
{
  c = abs(pos – c);
  c = min(c, 1.0 – c);

  return smoothstep(0.0, 0.002, sqrt(s) – sqrt(dot(c, c))) * -1.0;
}

float waterlayer(vec2 uv)
{
  uv = mod(uv, 1.0); // Clamp to [0..1]
  float ret = 1.0;
  ret += circ(uv, vec2(0.37378, 0.277169), 0.0268181);
  ret += circ(uv, vec2(0.0317477, 0.540372), 0.0193742);
  ret += circ(uv, vec2(0.430044, 0.882218), 0.0232337);
  ret += circ(uv, vec2(0.641033, 0.695106), 0.0117864);
  ret += circ(uv, vec2(0.0146398, 0.0791346), 0.0299458);
  ret += circ(uv, vec2(0.43871, 0.394445), 0.0289087);
  ret += circ(uv, vec2(0.909446, 0.878141), 0.028466);
  ret += circ(uv, vec2(0.310149, 0.686637), 0.0128496);
  ret += circ(uv, vec2(0.928617, 0.195986), 0.0152041);
  ret += circ(uv, vec2(0.0438506, 0.868153), 0.0268601);
  ret += circ(uv, vec2(0.308619, 0.194937), 0.00806102);
  ret += circ(uv, vec2(0.349922, 0.449714), 0.00928667);
  ret += circ(uv, vec2(0.0449556, 0.953415), 0.023126);
  ret += circ(uv, vec2(0.117761, 0.503309), 0.0151272);
  ret += circ(uv, vec2(0.563517, 0.244991), 0.0292322);
  ret += circ(uv, vec2(0.566936, 0.954457), 0.00981141);
  ret += circ(uv, vec2(0.0489944, 0.200931), 0.0178746);
  ret += circ(uv, vec2(0.569297, 0.624893), 0.0132408);
  ret += circ(uv, vec2(0.298347, 0.710972), 0.0114426);
  ret += circ(uv, vec2(0.878141, 0.771279), 0.00322719);
  ret += circ(uv, vec2(0.150995, 0.376221), 0.00216157);
  ret += circ(uv, vec2(0.119673, 0.541984), 0.0124621);
  ret += circ(uv, vec2(0.629598, 0.295629), 0.0198736);
  ret += circ(uv, vec2(0.334357, 0.266278), 0.0187145);
  ret += circ(uv, vec2(0.918044, 0.968163), 0.0182928);
  ret += circ(uv, vec2(0.965445, 0.505026), 0.006348);
  ret += circ(uv, vec2(0.514847, 0.865444), 0.00623523);
  ret += circ(uv, vec2(0.710575, 0.0415131), 0.00322689);
  ret += circ(uv, vec2(0.71403, 0.576945), 0.0215641);
  ret += circ(uv, vec2(0.748873, 0.413325), 0.0110795);
  ret += circ(uv, vec2(0.0623365, 0.896713), 0.0236203);
  ret += circ(uv, vec2(0.980482, 0.473849), 0.00573439);
  ret += circ(uv, vec2(0.647463, 0.654349), 0.0188713);
  ret += circ(uv, vec2(0.651406, 0.981297), 0.00710875);
  ret += circ(uv, vec2(0.428928, 0.382426), 0.0298806);
  ret += circ(uv, vec2(0.811545, 0.62568), 0.00265539);
  ret += circ(uv, vec2(0.400787, 0.74162), 0.00486609);
  ret += circ(uv, vec2(0.331283, 0.418536), 0.00598028);
  ret += circ(uv, vec2(0.894762, 0.0657997), 0.00760375);
  ret += circ(uv, vec2(0.525104, 0.572233), 0.0141796);
  ret += circ(uv, vec2(0.431526, 0.911372), 0.0213234);
  ret += circ(uv, vec2(0.658212, 0.910553), 0.000741023);
  ret += circ(uv, vec2(0.514523, 0.243263), 0.0270685);
  ret += circ(uv, vec2(0.0249494, 0.252872), 0.00876653);
  ret += circ(uv, vec2(0.502214, 0.47269), 0.0234534);
  ret += circ(uv, vec2(0.693271, 0.431469), 0.0246533);
  ret += circ(uv, vec2(0.415, 0.884418), 0.0271696);
  ret += circ(uv, vec2(0.149073, 0.41204), 0.00497198);
  ret += circ(uv, vec2(0.533816, 0.897634), 0.00650833);
  ret += circ(uv, vec2(0.0409132, 0.83406), 0.0191398);
  ret += circ(uv, vec2(0.638585, 0.646019), 0.0206129);
  ret += circ(uv, vec2(0.660342, 0.966541), 0.0053511);
  ret += circ(uv, vec2(0.513783, 0.142233), 0.00471653);
  ret += circ(uv, vec2(0.124305, 0.644263), 0.00116724);
  ret += circ(uv, vec2(0.99871, 0.583864), 0.0107329);
  ret += circ(uv, vec2(0.894879, 0.233289), 0.00667092);
  ret += circ(uv, vec2(0.246286, 0.682766), 0.00411623);
  ret += circ(uv, vec2(0.0761895, 0.16327), 0.0145935);
  ret += circ(uv, vec2(0.949386, 0.802936), 0.0100873);
  ret += circ(uv, vec2(0.480122, 0.196554), 0.0110185);
  ret += circ(uv, vec2(0.896854, 0.803707), 0.013969);
  ret += circ(uv, vec2(0.292865, 0.762973), 0.00566413);
  ret += circ(uv, vec2(0.0995585, 0.117457), 0.00869407);
  ret += circ(uv, vec2(0.377713, 0.00335442), 0.0063147);
  ret += circ(uv, vec2(0.506365, 0.531118), 0.0144016);
  ret += circ(uv, vec2(0.408806, 0.894771), 0.0243923);
  ret += circ(uv, vec2(0.143579, 0.85138), 0.00418529);
  ret += circ(uv, vec2(0.0902811, 0.181775), 0.0108896);
  ret += circ(uv, vec2(0.780695, 0.394644), 0.00475475);
  ret += circ(uv, vec2(0.298036, 0.625531), 0.00325285);
  ret += circ(uv, vec2(0.218423, 0.714537), 0.00157212);
  ret += circ(uv, vec2(0.658836, 0.159556), 0.00225897);
  ret += circ(uv, vec2(0.987324, 0.146545), 0.0288391);
  ret += circ(uv, vec2(0.222646, 0.251694), 0.00092276);
  ret += circ(uv, vec2(0.159826, 0.528063), 0.00605293);
return max(ret, 0.0);
}
vec3 water(vec2 uv, vec3 cdir, float iTime)
{
  uv *= vec2(0.25);
  // Parallax height distortion with two directional waves at
  // slightly different angles.
  vec2 a = 0.025 * cdir.xz / cdir.y; // Parallax offset
  float h = sin(uv.x + iTime); // Height at UV
  uv += a * h;
  h = sin(0.841471 * uv.x – 0.540302 * uv.y + iTime);
  uv += a * h;
  // Texture distortion
  float d1 = mod(uv.x + uv.y, TWOPI);
  float d2 = mod((uv.x + uv.y + 0.25) * 1.3, SIXPI);
  d1 = iTime * 0.07 + d1;
  d2 = iTime * 0.5 + d2;
  vec2 dist = vec2(
   sin(d1) * 0.15 + sin(d2) * 0.05,
   cos(d1) * 0.15 + cos(d2) * 0.05
  );
  vec3 ret = mix(WATER_COL.rgb, WATER2_COL.rgb, waterlayer(uv + dist.xy));
  ret = mix(ret, FOAM_COL.rgb, waterlayer(vec2(1.0) – uv – dist.yx));
  return ret;
}
void fragment() {
vec2 uv = UV;
  ALBEDO.rgb = vec3(water(uv * tile, vec3(0,1,0), TIME * distortion_speed));
}

Last edited 2 months ago by baiteryamato
Pizza
Pizza
2 months ago
Reply to  baiteryamato

Thanks, but I get a error message for your code:
error(16): Tokenizer: Unknown character #8211: ‘-‘

stormchild974
1 month ago
Reply to  Pizza

It is only because the dashed “-” got weird when copy pasting. It became another character that is not recognize, hence the error “unknown character”.
Just replace them by retyping “-“, for each error, then it will work 🙂

Last edited 1 month ago by stormchild974
stormchild974
1 month ago
Reply to  baiteryamato

Thank you very much! Perfect!