Saturday, February 22, 2014

Simple Voronoi Noise Generation

Voronoi noise is a very broad type of noise. It can look like many different things that don't seem to be related to one another. It can make the image below or (with some tweaking) it can make the background image of this website. It can make a beehive, or it can be a explosion dust cloud. It can even be used for things besides just noise. As you are probably beginning to realize, it is a very powerful tool in your noise generation arsenel.





Voronoi noise is very simple conceptually. Given a list of objects (points, lines, circles, etc.), the value of each pixel is the distance to the nearest object. In this tutorial we will focus on simple voronoi noise, which only uses points. This is because it lets us have periods like interpolated noise (so we can use it as the base for fractal noise), it simplifies the code, and it runs a lot faster with the correct optimazations.

The naive approach to simple voronoi noise is this:
generate a certain number of random points based on the periods given
iterate through all the pixels and set the value to the distance nearest point

This method would work. But it is slow. And you get "clumps" of points right near each other and other areas with none. As it turns out, we can kill both of those birds with one stone, if we use cell checking. Cell checking is quite simple. You divide the area up into a grid of cells, and put one point at a random location in each cell. Because there is guaranteed to be at least one point in each cell (in this case only one point), you know that the nearest point is going to be either in the current cell, or one of its neighbors. It also reduces the clumps by forcing the points to be more evenly spread.

In psuedo-code, it would look something like this:
double[][][] cells = generateCells(periodX, periodY);
for(int x = 0; x < noise.getWidth(); x++)
{
    for(int y = 0; y < noise.getHeight(); y++)
    {
        double minDis = Double.POSITIVE_INFINITY;
        for(int i = -1; i <= 1; i++)
        {
            for(int j = -1; j <= 1; j++)
            {
                minDis = Math.min(minDis, checkCell(i, j, x, y, cells));
            }
        }
        noise[x][y] = minDis;
    }
}

But there is more to Voronoi noise than that. To get even more effects, we add in two more things: a distance function and a combine function. If, for example, we don't always use real (Euclidian) distance, we can get a lot more effects, without all that much work. Likewise, sometimes we don't use the closest point. Instead we might use the second closest or the third minus the first. It complicates the code a little bit, but nothing like Perlin or Simplex noise. The actual code is a bit long, so I won't post it here. Refer to the sources for the real thing.

Distance Functions:
Euclid = "standard" distance
Manhattan = x and y difs added
Chebyshev = max x or y dif
Minkowski 0.5 = sqrt of difs multiplied together

Combine Functions:
F1 = closest point
F2 = second point
F3 = third point
F2_F1 = second minus first
F3_F1 = third minus first
F3_F2 = third minus second
F3_F2_F1 = third minus second plus first

Voronoi noise is not like other noises, it doesn't even come close to playing nicely with the softly enforced 0 to 1 range of typical noise. To fix this, we normalize the noise. Normalization is just resizing the array so the minimum value is 0 and the maximum is 1.

Simple voronoi noise is also a valid fractal base noise function, due to the fact that is supports periods. This is how you would generate the explosion clouds I mentioned.

Simply grab only the pixels above yellow, maybe add some black in there, and you got a nuclear explosion viewed from the top.

Like always, an applet. I would recommend viewing the noise in black and white, because it looks the best that way.
Controls:
Space = next distance function
X = next combine function
Q = increase x period
E = decrease x period
A = increase y period
D = decrease y period
S = new random seed
Shift = toggle color mode
Enter (downloadable version only) = save screenshot


If the applet doesn't load, trying refreshing the webpage. May not work on mobiles.

Demos: https://drive.google.com/folderview?id=0B_jXYEquMamINGVGQTM0cTJzdmM&usp=sharing
Source Code: https://github.com/f4113nb34st/Println/

No comments:

Post a Comment