Real-Time Flow Map Generation

Background

In Portal 2, flow maps are used to create flow patterns for the water elements in the game (i.e. the poisonous swamps), which have proven to improve gaming experience. By sampling from the ﬂow map, every point on the water surface gets a unique 2D vector for normal perturbation. Although we don’t need high resolution ﬂow maps, it’s impractical to hand-draw a ﬂow map for each level. A better way than hand-drawing would be generating from 3D modeling packages such as Houdini, which is what was done in flow map generation in the Portal 2 game: each level has a static ﬂow map for the pixel shader to sample from. However, these static ﬂow maps do not provide interactions between the players and the water surfaces, nor are they able to handle the situation when new geometries are dynamically added to the level.

A ﬂow map is, by its deﬁnition, a texture representation of the velocity ﬁeld. In our application, the velocity ﬁeld is updated every timestep by solving the Navier-Stokes equations, ﬂow map texture is generated by blending the colors of four vertices in a quad, whose value is determined by the two dimensions of the corresponding velocity vector.

Method

Combining physically accurate fluid solvers and solid textures is promising method of achieving complex fluid behaviors in computer graphics. The incompressible Navier-Stokes equations has the following form:

The fluid solver used in the application is based on Jos Stam’s Stable Fluids paper. Four key functions are implemented: (a) Source: initialize the velocity field with user input. (b) Diffusion: discretize the diffusion operator and solve the linear system. (c) Projection: divide the velocity field into a divergent part and a divergent free part; subtracting the divergent part of the velocity field and the resulting field is divergent free. (d) Advection: the velocity field is advected by itself; if there is any other field in the simulation (texture coordinate or fluid density), this new field is advected by the velocity field.

As shown in Fgure 1, the velocity ﬁeld can be rendered as a collection of quads, with the color at each vertex being the two dimensions of the 2D velocity vector, and the third channel 0.

Figure 1: Render to a quad: the colors at the four vertices are the value of the velocity ﬁeld

We store the velocity ﬁeld to a texture which clamps the pixel value in each channel to range [0, 1], and in the fragment program, the sampled colors are normalize to the range [-1, 1]. Without external force, the inital ﬂow should be static, although the normalized vector produces a ﬂuid ﬂow with a constant negative velocity, because a zero vector, (0; 0), in the texture produces a vector of (1; 1) after normalization. The solution to this artifact is to transform the velocity vector by an offset of (0:5; 0:5), which renders the initial ﬂow map to brown (shown in Figure 2).

Figure 2: Initial ﬂow map without disturbence

When adding new objects into the simulation environment, we register the objects and update the boundary conditions in the simulation accordingly. For a regularly shaped object, for instance, a box, the velocity vector closed to the edge of the box is set to change to the opposite direction (Figure 3).

Figure 3: Flow map when adding objects

Result

Our ﬂuid solver is based on the Navier-Stokes equations, so the behavior of the ﬂuid ﬂow is physically accurate (Figure 4).

Figure 4: Use the ﬂow map for ﬂuid surface normal perturbation: left: ﬂow map; right: simulation environment