# How to implement this kind of ripples with a GLSL fragment shader?

So I have already implemented the reflection part:

uniform sampler2D texture;
uniform vec2 resolution;
uniform vec3 overlayColor;

void main()
{
vec2 uv = gl_FragCoord.xy / resolution.xy;

if (uv.y > 0.3)// is air - no reflection or effect
{
gl_FragColor = texture2D(texture, vec2(uv.x, uv.y));
}
else
{
// Compute the mirror effect.
vec4 color = texture2D(texture, vec2(uv.x, 0.6 - uv.y));
//
vec4 finalColor = vec4(mix(color.rgb, overlayColor, 0.25), 1.0);
gl_FragColor = finalColor;
}
}


Now the question is how are these ripples implemented?

• This is no complete answer, but a series of hints: you need an uniform to "animate" the effect - i.e. a time-like variable. Using that time value, you can shift the uv.xy with a (sin(time),cos(time)) offset vector. Of course, you must figure out the amplitudes of the sine and cosine offsets. I'd start with just offsetting the uv.y first and see how I can adjust the effect further. – teodron Jan 2 '15 at 12:02
• Thank you so much for these hints. It turned out this is what I need after trying @LeFauve's implementation. – cepro Jan 2 '15 at 16:30

I tried to implement what teodron suggested:

void main()
{
vec2 uv = gl_FragCoord.xy / resolution.xy;
float sepoffset = 0.005*cos(iGlobalTime*3.0);
if (uv.y > 0.3 + sepoffset)// is air - no reflection or effect
{
gl_FragColor = texture2D(texture, vec2(uv.x, -uv.y));
}
else
{
// Compute the mirror effect.
float xoffset = 0.005*cos(iGlobalTime*3.0+200.0*uv.y);
//float yoffset = 0.05*(1.0+cos(iGlobalTime*3.0+50.0*uv.y));
float yoffset = ((0.3 - uv.y)/0.3) * 0.05*(1.0+cos(iGlobalTime*3.0+50.0*uv.y));
vec4 color = texture2D(texture, vec2(uv.x+xoffset , -1.0*(0.6 - uv.y+ yoffset)));
//
//vec4 finalColor = vec4(mix(color.rgb, overlayColor, 0.25), 1.0);
gl_FragColor = color;
}
}


It looks pretty close (it's hard to tell without the base image) but you can tweak the parameters.

You may see it in action there: https://www.shadertoy.com/view/Xll3R7

Some remarks:

• I had to invert the y coordinate since I was getting the image upside down, but it may depend of what you pass into resolution.xy; if the result is inverted for you, just uninvert uv.y
• I changed your uniform declarations so it works with shadertoy. You can ignore those changes.
• You will need however to add a uniform providing the time and use it in place of iGlobalTime (which is the time in seconds)
• I added a tide effect since it looks like there is one on your example but it's hard to tell (see sepoffset variable). You may remove it if you don't like it
• I removed the overlay color since it was not looking good, and your example didn't had one
• To tweak the effect to your taste:
• change the factor of iGlobalTime to speedup/slowdown the effect (you can change each of them separately if you want, let's say accelerate the x movement and slow down the y movement)
• change the cos() factor to amplify/attenuate the effect

EDIT: I changed the yoffset to include the modification from @cepro

• Great effort! +1 – teodron Jan 2 '15 at 15:22
• Thank you for your help :). This really does give a pretty close result. But I think it misses one last ingredient. Notice, in the picture, that the closer those ripples are to the camera (bottom of the screen) the bigger they are (vertically stretched). So maybe we need to scale the y offset by the uv.y? float yoffset = ((0.3 - uv.y)/0.3) * 0.05*(1.0+cos(iGlobalTime*3.0+50.0*uv.y));. I have tried this and I kinda like the result. – cepro Jan 2 '15 at 17:06
• Good catch for the closer ripples @cepro. I missed it – LeFauve Jan 3 '15 at 7:12
• IMO there's something wrong with the modified wave pettern. While the waves increase for me, they've got that odd "mirrored" pattern in them (GTX 680 in latest Chrome). – Mario Jan 3 '15 at 8:41