Recently I've had a lot of fun making live wallpapers for Android with the mighty LibGDX framework. While live wallpapers are basically the same like every other app, they also benefit from OpenGL ES, which allows us to use shaders and thus creating nice effects. In this article I'll try to explain how I achieved the water droplet effect in my Wet Glass live wallpaper.
We'll be using a frame buffer and custom shaders, so only devices that support OpenGL ES 2.0 can actually display this. That would be any device running Android 2.1 or newer. In case you were wondering why my live wallpaper requires Android 3.0 note that I'm using Dialogs in the configuration app.
The rendering consists of two parts: First, drawing a couple of droplets in the frame buffer and second, drawing the frame buffer texture applying the actual effect shader.
The droplets - when not moving - are nothing more than the normal map of a sphere so the texture being rendered in the frame buffer (see right) contains pretty much the depth and direction of the droplets' surfaces towards the viewer and is a normal map itself. The shader will need this later.
When the frame buffer is done the effect shader should be enabled and the frame buffer texture can be drawn to fit to the screen. The shader will then do some mysterious calculations (we'll get to that later) to distort and draw a backdrop image.
Since most mobile devices suffer from a terribly low memory bandwidth, I gave the users the option to scale down the frame buffer texture size to counter this propblem (the shader performance will benefit from this). By default, the frame buffer texture is half as big as the power-of-two texture that would fit the screen. This greatly increases the performance although the visual difference is only minimal. Extensively decreasing the size of the frame buffer gives interesting results and might be a way to achieve interesting effects, but that's a different topic.
Aside from the refraction effect the movement pattern and trail shape of the droplets is very important for the effect to look good. I never tried to make a photorealistic approach, it just had to look good and authentic.
The trail is the same as most particle trails a set of quads in which each quad has its southern vertices aligned to its parents northern vertices. The texture the trail mesh uses the same texture as the droplet but not the same UV coordinates. As you might have figured from the image shown above the trail mesh only uses a small horizontal stripe from the texture. To improve the effect, maybe the UV coordinates could be rotated to fit the orientation of the quad. The trail elements decrease in size as long as they live and die when their size falls below a certain threshold.
Each droplet moves along a sinus curve, all of them with different wavelengths and amplitudes. Of course the amplitude delta should be scaled randomly in each frame.
While the idea behind the shader is actually quite simple, it took me a long time to fine tune it. Also, the code is pretty cryptic which is why I don't publish it here.
The shader needs the background texture and the normal map from the frame buffer. Then it basically uses the normals absolute x and y coordinates as UV values multiplied with the alpha value plus a little offset to draw the background texture.
Before this approach I tried to draw the normal map only over a certain alpha value threshold to achieve a metaball'ish fluid effect but of course you cannot simply blend normal maps so the droplets would look somewhat flat and heavy so a trail mesh seems to be the best bet.
Thanks for reading my first article here so far. I'm on Twitter in case you want to drop a line.