Warp Map

Warp Map

I saw an advert for some smooth and creamy beer on TV the other day. They show you a close up shot of the beer, having just been poured, and the millions of tiny bubbles warping around inside the glass. Flowing and folding in on each other in that nice, just poured milk in the tea, kind of way.
So I was thinking about how this might be possible to reproduce graphically. Here's a method that, although is not quite as beautiful, it still pretty fascinating.

This article follows on from the previous one entitled Introduction to Feedback. I shall explain how to warp a picture slightly, and how to change the warp from frame to frame to create a very effective fluid flow effect.

The Warp Map

This is a dead simple method really, but I am finding it hard to explain, so stop me if I fail to make sense at some point.

You have an image, and the aim is to warp this picture in some way.

Imagine splitting this image up into squares.

Now imagine that those nice and neat squares are suddenly set all wonky. Note that only the squares have changed, the underlying image is the same.

Now those wonky squares can be bent back into their propper shape. As they are bent back, the image is bent along with them.

What you get is a wobbly, wonky image.

No big deal really, wonky images are two a penny these days. But what happens if you feed the wonky image back into the system? You end up with an even more wonky image. If you constantly feed the image back, the image will appear to flow, like a you just put a spoon in it and stirred.

The warp map becomes a flow map.

Different parts of the image will flow in different directions. Those directions are defined by the way in which the squares are deformed. You can make any part of the image flow in any direction you want simply by altering the offset of the vertices that make up the squares.
The picture shows the original squares (green), the deformed squares (red), and the directions in which the image will flow (yellow).

Now, it would be quite boring if your image constantly flowed the same way. To make things more interesting, you can alter the flow map slightly each frame, thus changing the way the image flows.

How should you change the flow map?

Changing the flow map simply means changing the positions of the vertices that define the squares.

  • You can try using some sinusoidal functions to wobble the vertices over time.
  • You could move each vertex by a small random amount each frame.
  • You can treat the grid as a gel (see article on gel simulation) and have the grid wobble over time.

    This last method is by far the best. You get an uneven, natural looking pattern of flow. Vertices close together tend to move together, and the overall net flow is close to zero.

    Numerical Inaccuracy

    Because this method is operating on a pixel level, numerical inaccuracies will creep in extremely quickly. The original picture will be unrecognisable within just a few frames. There is very little that can be done about this, other than doing it at a very much higher resolution. But this is no real worry. This method is most useful for adding the appearance of flow to moving images. I shall explain this later.

    Implementing the flow map

    I do not intend to present a full description of an entire flow program, as it would obviously take up lots of room. All I shall explain is how to texture map onto a single square from a wonky square.

    So we'll take every pixel in the straight square, and calculate which pixel that relates to on the wonky square.

    The four vertices of the wonky square will be called A, B, C and D. I am assuming that you have some way of using fixed point numbers here. This will clearly be faster than using floats.
    Note: If you are using Fixed Points, don't forget to convert those divides by 16 into bit shifts.

    Variable Declarations
     FIXEDPOINT TX1, TY1, TX2, TY2, tx, ty
     INTEGER x, y
    Code Begins
     VLDx = (Cx - Ax) / 16          'Rate of change of X down the left side of the wonky square 
     VRDx = (Dx - Bx) / 16          'Rate of change of X down the right side
     VLDy = (Cy - Ay) / 16          'Rate of change of Y down the left side
     VRDy = (Dy - By) / 16          'Rate of change of Y down the right side
     TX1  = Ax
     TY1  = Ay
     TX2  = Bx
     TY2  = By
     loop y from 0 to 15
            HDx  = (TX2-TX1) / 16   'Rate of change of X across the wonky polygon
            HDy  = (TY2-TY1) / 16   'Rate of change of Y across the wonky polygon
            tx = TX1
            ty = TY1
            loop x from 0 to 15
                    Image2(x, y) = Image1( int(tx), int(ty) ) 
                    tx = tx + HDx
                    ty = ty + HDy
            end of x loop
            TX1 = TX1 + VLDx;
            TY1 = TY1 + VLDy;
            TX2 = TX2 + VRDx;
            TY2 = TY2 + VRDy;
     end of y loop

    Now for a couple of goodies.

    This is a fairly raw implementation of the flow map. A picture is simply allowed to flow. However, it is also smoothed slightly each frame. It produces a very pleasing pattern, like mixing paint. Don't look at it too long, as you will begin to see swirling patterns behind your eyelids whenever you sleep.

    If you really want it, here is the main bit of the source code to this program. It is missing the Fixed Point Library.

    I applied the flow map to my fire routine, and the effect was fantastic. Rather than simply traveling up linearly, the fire now swirls around and produces realistic toungs of flame.