Rendering Flow Fields with a Polyline

Flow fields in GeeXLab

Few days ago, I read a cool article about flow fields.

What is a flow field?

A flow field is two-dimensional area where each point has a different value.But these aren’t just random values. A particular point has a particular value and as you move out from that point to neighboring points, you get similar, but gradually changing values. In flow fields, these values are usually interpreted as directions. So if you map your values so they are between 0 and 360, they can be directly used as degrees of direction.

In a word, just think to the position/orientation of iron filings in a magnetic field.

The author of the article has coded its demos in Javascript in a 2D canvas. And with few lines of code like these ones:

for(var x = 0; x < width; x += res) 
  for(var y = 0; y < height; y += res) 
    var value = getValue(x, y);
    context.translate(x, y);
    context.moveTo(0, 0);
    context.lineTo(10, 1);

he was able to render image like this one:

Flow fields in Javascript

Seeing this image, I wondered how could I render this kind of image with GeeXLab. The answer was simple: using a polyline.

In GeeXLab, a polyline can be seen as a super line. A polyline is a collection of single lines. These lines can be connected or not. In our case we will use the polyline as a set of individual lines. Polylines can be coded using the gh_polyline lib available in Lua and Python.

I already played with polylines in this article.

I coded a GeeXLab demo and I tried to produce a code similar to the Javascript one, with rotate(), moveTo() and lineTo() functions. Here is a code snippet in Lua of the FRAME script:

local w2= winW/2
local h2= winH/2
g_vertex_index = 0
for i=1, g_num_lines do
  local x = random(-w2, w2)
  local y = random(-h2, h2)
  translate(x, y)
  ang = getValue(x, y)
  moveTo(0, 0)
  lineTo(10, 1)

The translate(), rotate(), moveTo() and lineTo() functions are very simple because they only set some variables. The real work takes place in the stroke() function which uses the previous variables to set a new line with gh_polyline.set_vertex_position().

If you look at the source code of the demo, you will find the code of the previous functions:

function translate(x, y)
  g_pivot_point.x = x
  g_pivot_point.y = y
function moveTo(x, y)
  g_moveto_point.x = x
  g_moveto_point.y = y
function lineTo(x, y)
  g_lineto_point.x = x
  g_lineto_point.y = y
function getValue(x, y)
  local PI = 3.14159
  return (math.sin(x * 0.007 + g_time) + math.sin(y * 0.007 + g_time)) * PI * 0.75
function rotate(angle)
  local s = math.sin(angle)
  local c = math.cos(angle)
  -- translate point back to origin
  g_lineto_point.x = g_lineto_point.x - g_moveto_point.x;
  g_lineto_point.y = g_lineto_point.y - g_moveto_point.y;
  -- rotate point
  local xnew = g_lineto_point.x * c - g_lineto_point.y * s;
  local ynew = g_lineto_point.x * s + g_lineto_point.y * c;
  -- translate point back
  g_lineto_point.x = xnew + g_moveto_point.x;
  g_lineto_point.y = ynew + g_moveto_point.y;
function stroke()
  if (g_vertex_index < (g_num_vertices-2)) then
    local x = g_pivot_point.x + g_moveto_point.x
    local y = g_pivot_point.y + g_moveto_point.y
    gh_polyline.set_vertex_position(polyline, g_vertex_index, x, y, 0, 1)
    g_vertex_index = g_vertex_index + 1
    x = g_pivot_point.x + g_lineto_point.x
    y = g_pivot_point.y + g_lineto_point.y
    gh_polyline.set_vertex_position(polyline, g_vertex_index, x, y, 0, 1)
    g_vertex_index = g_vertex_index + 1

Once the polyline has been updated, it’s rendered with :


You can find the demo (available in three versions) in the full code sample pack in the gl-21/flow-fields/ folder. This demo requires GeeXLab because the demo_v3 calls a new function that sets vertex position and color at the same time: gh_polyline.set_vertex_position_color().

Here are a video and some screenshots:


Flow fields in GeeXLab
Flow fields in GeeXLab


Flow fields in GeeXLab