# how to add water effect to an image

This is what I am trying to achieve: A given image would occupy say 3/4th height of the screen. The remaining 1/4th area would be a reflection of it with some waves (water effect) on it.

I'm not sure how to do this. But here's my approach:

• render the given texture to another texture called mirror texture (maybe FBOs can help me?)
• invert mirror texture (scale it by -1 along Y)
• render mirror texture at height = 3/4 of the screen
• add some sense of noise to it OR using pixel shader and time, put pixel.z = sin(time) to make it wavy

(Tech: C++/OpenGL/glsl)

Is my approach correct ? Is there a better way to do this ? Also, can someone please recommend me if using FrameBuffer Objects would be the right thing here ?

Thanks

I assume you're after this kind of old-school, 2d effect:

If so, you're correct.

1. Render your "real" frame to an FBO.
2. Render the top part to the framebuffer using a simple textured quad, using the FBO as the texture.
3. Render the bottom part mirrored, with some horizontal waves.

You have several options on how to achieve the third. The simplest way would be to render one pixel high textured spans, stretch and offset them. Alternatively you could use shaders and do even more interesting effects.

Other things to try include tinting the mirrored version towards blue a bit, as well as varying the brightness of the scanlines ("wave" them too).

You can also grow the waves further away from the mirroring point.

This effect is also completely possible with good old plain opengl 1.x, even without FBOs. Render to texture and use glReadPixels to read the top part back to system memory, upload it as a texture and then do the scanline-by-scanline rendering. This, however, is so slow that if you can use FBOs, it's always a much better option.

EDIT: suggestions for the shader bit

I recommend doing these step by step, so you'll see what each change does, and adjust them based on what you're after.

• Render the mirrored bit, top-down.
• Adjust the horizontal texture coordinate (u or v, depending. I'm assuming u here) with sin() function, such as:

u+sin((v+t)*FREQ)*AMP

where FREQ and AMP are constants you'll find by trial and error. Both are below zero. Let's say start with 0.1. 't' is a time constant, probably a float uniform.

• Scale the waviness so that it's weaker near the mirror line, like:

u+(sin((v+t)*FREQ)*AMP) * v

or possibly (1-v), depending on how the texture is oriented. You may wish to increase AMP after this change.

• Since the texture coordinates go outside the 0..1 range, you may wish to scale it back, like..

u+((sin((v+t)*FREQ)*AMP+AMP)/(1.0 + 2*AMP)) * v

Depending on the scene you're rendering, the above may look worse than letting it wrap.

Note though that all the calculations above are off the top of my head without texting, and may contain mistakes, but that's the basic principle anyway. You may also want to try swapping u and v for another kind of wavy effect, or even combine the two.

• Thanks for the explanation. I was new to FBOs and such, so finally I reached step 3 where I can mirror a texture using FBOs. Now, all I need is a way to add 'wavy water' effect to it. I would like to use some shader technique to do it. Would you happen to have any suggestions for that ? – brainydexter Feb 21 '11 at 4:51
• Thanks for the explanation. I actually ended up using a variant of the above. But, I'll give these flavors a try and see how they turn out to be. – brainydexter Feb 21 '11 at 16:30
• Note: If you're supporting FBO fallbacks, then instead of glReadPixels, use glCopyTexSubImage2D. – mid Oct 1 '19 at 13:08

You can find a nice looking water tutorial here and check out this link for screenshots of the effect. There are a number of ocean shaders that you can have a look at for a more realistic water effect than a sine wave.

There's lot of papers, articles, shaders etc here which ranges from fairly intermediate to advanced, and they use OpenGL and GLSL.

Hope that helps.

brainydexter, check out GeeksLab, it has a nice "water/ripple" shader. It's not simulating water but a ripple. Maybe this helps you a bit: