Flow maps are a simple way to get some movement into your shader. Valve and The Wild External have documented the process pretty throughly.
I thought I’d try a GLSL/Three.js implmentation.
Flow Maps
Flow maps are texures that uses the red and green channels to offset pixels vertically and horizontally.
For example a value of 0 in the red channel will move the pixel fully to the left, 0.5 will not move at all and 1 will move all the way to the right. How much the pixel is moved is scaled based on the flow speed and time value.
Here’s the shader code to get the flow direction from the shader map. It takes the color value, which in the 0 to 1 range, and rescales into a -1 to 1 range.
vec2 flowDirection = (texture2D( flowMap, vUv ).rg - 0.5) * 2.0;
Here’s a flow map that will move in a roughly circular shape.
Using that flow map let’s move the pixels in a water texture:
Next I’ll add a time offset to make the flow move over time, with a time reset every 3 seconds.
Here is how I calculate the time cycle, normalised between 0 and 1:
float timeScaled = time / 3;
float timeCycle = timeScaled - floor(timeScaled);
As you can see the water flows well, but becomes more distorted over time. The trick to solve this is to have two flows that are offset by half and lerp between the two flows. When one flow is being reset the other flow is fully visible.
Here’s how you lerp between the two:
gl_FragColor = mix( waterColor1, waterColor2, abs(cycleTime-0.5)*2.0 );
And here’s the final result.
Don’t forget you can view source on this page for more implementation details.