Submitted by , posted on 25 June 2002

Image Description, by

Lots of novel things happening here...

First of all, you can use the mouse to rotate the window on top of your desktop. The simulator responds to this by simply rotating the gravity vector. These forces have been used to form a breaking wave in the image above.

Secondly, the literature on which the simulation is based distributes marker particles throughout the liquid area, but I developed a way to track the liquid/air interface requiring particles only near the surface. These particles are reseeded every frame based on dynamic rules which also help converse mass better. (Although, since the computational mesh is anisotropic, screwing with gravity adversely affects this.)

I also came up with a novel technique to render the liquid. I'll describe it here since the idea is applicable to any 2D or 3D particle system. (The demo only distributes particles around the liquid surface but assume here that the liquid is entirely a 2D particle system.) The approach is a hardware implementation of the classic 2D metaballs effect, which basically amounts to thresholding a summation of 2D density functions...

First I procedurally generate a Gaussian density function in a 16x16 alpha texture-map and set up a texture which can be rendered to, which I'll refer to as the p-buffer. Now, for each frame, I first clear the p-buffer to the colour (0,0,0,0), set the vertex colour to (0,0,0,1) and enable blending with ONE/ONE as the src/dest functions. Then I render each particle into the p-buffer as a 16x16 pixel quad, texture-mapped with the density function. After this, I set the vertex colour to (1,1,1,0) and render another quad which covers the entire p-buffer. This can be mapped with a texture of your choice. We've just completed the summation of the density functions for each metaball. To perform the thresholding all we need do is enable alpha-testing, set the function to 'greater than whatever threshold you choose' and render a quad to your frame-buffer, texture-mapped with the p-buffer.

You'll notice in the demo that the liquid surface is also outlined. To achieve this, we start by filling the alpha channel of the p-buffer exactly as above. From here we render a quad mapped with an "ink" texture to the p-buffer, and render a quad mapped with the p-buffer to the frame-buffer, same as above. To create the effect of an outline we now render a second pass (using our original map) opaquely on top of the ink pass, but using a slightly smaller threshold so that a "band of ink" from the first pass remains visible. This means we need to write a new texture-map into the RGB channels of the p-buffer, making sure not to modify the alpha channel. To do this, we could just mask off writes to the alpha channel but this was incredibly slow on my GeForce. A better solution is to first zero the RGB channels of the p-buffer by setting the src/dest blend functions to ZERO/SRC_COLOUR, the vertex colour to (0,0,0,1) and rendering a non-texture-mapped quad which covers the p-buffer. Now we can set the blend functions back to ONE/ONE and the vertex colour back to (1,1,1,0) and proceed to render the second pass exactly as before but remembering to use a smaller threshold.

This same method can also be used to render level set representations of 2D liquid or fire by simply copying the distance grid to an alpha texture of equal dimensions each frame and letting bilinear filtering interpolate the distances. In the case of fire, multiple passes, each with a different alpha-testing threshold, can be used to render different parts of the flame with different texture-maps. Alternatively, a spectrum could be defined in a 1D texture-map which is looked-up using the interpolated distance values.

The "looking through liquid" effect is nothing more than a preprocessed 512x512 capture of the desktop. The procedure I came up with involves applying two wave deformations, blending in a a bluish tint with Gaussian noise and applying two Gaussian filters. Of course, in the real world refraction doesn't occur when looking through a tank of water like this but I thought the waviness looked nice.

You can download the demo here:

It has been tweaked and tested only on my PIII-700 running Windows 2000 with a GeForce 1 and I'm using OpenGL extensions which I think require at least 28.32 drivers. There will be a small delay when you run the program to generate the textures. Performance is fill-rate bound on my configuration so by default the demo takes three Euler steps (the time-step is fixed for stability reasons) per frame giving me 35 FPS. You can specify this ratio yourself with the number keys however and I suggest you try this. You can also toggle the ink pass by pressing 'i'. To quit either press escape or change focus from the window. Finally, you may notice that sometimes little "explosions" occur when the water velocity gets too high and the simulator becomes unstable, so be gentle. Also note that I took out the anti-aliased window edges and reflective glass pane feature (shown above) to accomodate the unconventional window styles of WinXP.

If for some reason you can't run the demo, you can download a 512x512 DivX movie of the above executable running on my computer here:

Image of the Day Gallery



Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.