- Edited
You can see my change to the shader here. IMHO it looks a great deal better than here.
I'm not so smart that it was on purpose, but the dark lines on the tiles under the water prevent the player from noticing the white foam from not matching up from tile to tile.
I'd also like to provide my code for anyone to play around with:
Click to reveal Click to hide
shader_type canvas_item;
uniform sampler2D whites; // a image of just the water foam whites
uniform sampler2D waterTile; // water tile texture
uniform sampler2D vectors; // vectors showing water flow direction for each tile
uniform vec2 tileSize = vec2(62.0,62.0);
uniform vec2 tileMapSize = vec2(26.0, 20.0); // number of grid tiles
uniform float opacity : hint_range(0, 1);
uniform float waveAmplitude = 0.2;
uniform float waveFrequency = 2.0;
uniform float blendingAmount = 0.6;
vec4 getAverageColor(vec2 uv) {
// Compute the offsets for sampling neighboring pixels
vec2 dx = vec2(1.0 / tileSize.x, 0.0);
vec2 dy = vec2(0.0, 1.0 / tileSize.y);
// Sample the neighboring pixels and average their colors
vec4 sum = texture(waterTile, uv);
sum += texture(waterTile, uv + dx);
sum += texture(waterTile, uv - dx);
sum += texture(waterTile, uv + dy);
sum += texture(waterTile, uv - dy);
return sum / 5.0;
}
vec2 wave(vec2 uv, float time) {
return vec2(
uv.x + sin(uv.y * waveFrequency + time) * waveAmplitude,
uv.y + sin(uv.x * waveFrequency + time) * waveAmplitude
);
}
vec2 grid(vec2 uv, float columns, float rows){
return fract(vec2(uv.x * columns, uv.y * rows));
}
void fragment(){
ivec2 cd = ivec2(floor(UV * tileMapSize));
vec4 flowColor = texelFetch(vectors, cd, 0);
// float dist = flowColor.w; // I had also previously passed in water tile to land distance
// convert color from velocity to actual vec2
vec2 velocity = (flowColor.xy * 2.0 - vec2(1.0)) * flowColor.z * 15.0;
// convert image UV to grid cell UV
vec2 gridUV = grid(UV, tileMapSize.x, tileMapSize.y);
// apply wave effect to UV
gridUV = wave(gridUV, TIME);
// get additional foam contribution
vec4 foam = texture(whites, gridUV - velocity * TIME);
gridUV += -1.0 * velocity * TIME;
vec4 c = getAverageColor(gridUV) * (1.0 - blendingAmount);
if (foam.w > 0.5){
c.xyz += foam.xyz * flowColor.z; // foam color is a product of velocity length (passed in also from cpu)
}
c += texture(waterTile, gridUV) * blendingAmount;
c.a = opacity;
COLOR = c;
}