How To Make A Dynamic Triangle Background Effect

Triangle background When I was making HexMatch, I wanted to stay with an abstract, geometrical style, but I also wanted the background to be dynamic and interesting. That made me think of some videos I saw of Loren Bednar's game, Depth Check: Neptune. They had a field of triangles with shifting, swirling colors that evoked the depths of the ocean. Slight variations in saturation gave it character, almost like each triangle was hand-made, in contrast to the uniformity of the triangles themselves. I took a guess at how it might be implemented and got lucky, and after a few hours one Sunday morning I had a background that was even cooler than I'd envisioned.

Here is what we're making:

Looks like your browser doesn't support Flash or has it disabled.

You can jump right into the sample code. I implemented it in Haxe and OpenFL, but the effect is easy to implement anywhere that triangles can be drawn. Let's start with the high level concept.

Concept

The idea is to fill the window with uniform triangles, and then change the color of each triangle in a smooth but random pattern. Depth Check uses isosceles triangles, but since HexMatch was about hexagons I wanted to use equilateral triangles arranged as hexagons. The hexagon page at Red Blob Games has all the math I needed to create the triangle vertices.

The colors of the triangles needed to change smoothly but unpredictably. One easy way to make a sequence of random values that change smoothly is to use Perlin noise. Flash can make colored Perlin noise, but to have more control over the colors I used the noise as an index into a color gradient. By stepping through the noise buffer on each frame, the color of each triangle will move smoothly back and forth through the gradient. Each triangle starts at a different place in the buffer, so they seem to change with different patterns. However, since the pattern does repeat in each triangle in turn, there is the illusion of motion across the window.

Implementation

First we need to draw triangles in the window. The best way to draw a bunch of triangles in Flash is with the drawTriangles method in the Graphics class. This is similar to the OpenGL call glDrawElements. The method takes a vertex array, a texture coordinate array, and an index array. The index array refers to the other two arrays, and every three entries defines the corners of a triangle.

The vertex array is filled using the hexagon coordinates. The arrays are constructed so that every triangle is independent, so the index array is just index[i] = i. The index and vertex arrays are created at initialization and don't change again.

The texture is the color gradient. It is essentially one-dimensional, but Flash 11 requires it to be at least two pixels high (don't ask me why). You can use an image, or create the gradient at runtime by drawing a rectangle with a gradient fill and drawing it to a BitmapData. Just be sure that the image wraps horizontally, otherwise there will occasionally be abrupt color changes.

The Perlin noise is created using the perlinNoise method of the BitmapData class. This isn't supported in the HTML5 target of the OpenFL version I have (1.0.5), so if you need to build for HTML5 save the noise bitmap to a file and use that instead of creating it at runtime. After the noise is created, get a vector of the pixels, extract one color channel, and normalize all the noise so it's between 0 and 1. That way it can be used directly as a texture coordinate. Play with the parameters of the perlinNoise method to get different effects.

The texture coordinate array is filled during each frame by sampling the Perlin noise for each triangle. The u coordinate is set to the noise sample, while the v coordinate is set to 0.5 to sample the middle of the texture vertically. On each frame, start at an offset and sample consecutive noise values for each triangle, wrapping at the end. Increment the offset at the start of each frame so the triangles move through the pattern. Going through the triangles consecutively led to a weird effect where the pattern rotates around a hexagon then moves to the next one.

triangles[i].u = noise[(offset + i) % noise.length]

Much more interesting patterns emerge if we use a prime number to skip through the triangles.

triangles[(i * prime) % triangles.length] = noise[(offset + i) % noise.length]

It is important that the number is not a factor of the length of the triangle list, and vice versa. If one is a factor of the other, then the index will repeat too early and miss some triangles. That is why the factor should be a prime number larger that the length of the triangle list. Try different prime numbers, they make the overally effect evolve in different ways.

Although I've been writing "each frame," this effect is subtle enough that it can be updated at a low frame rate without breaking the illusion. Updating can even be paused briefly without really standing out. For example, in HexMatch the background is only updated ten times per second, and it pauses when there is any other animation active.

Conclusion

This turned out to be a really cool effect with a lot of potential. Changing the noise parameters, the color gradient, and the prime factor all lead to a wide range of effects. It's also a relatively cheap effect, because it can be updated at a low frame rate and paused when necessary.

Let me know if you implement this on another platform so I can add a link.