Procedural Racetracks

Today's post will be about procedural racetracks. That's what I've chosen as representation, that is. It could be something different. But right now, it's a racetrack.

Really, what we are dealing with is a Perlin noise curve turned into a curve. Again, images are better than words, and animations better than images - best of all, though, is an active embed, as can be seen below:





The above is a procedural racetrack that is constantly changing. It is quite quick to generate too, being regenerated several times a second, and morphing between different configurations. Neat, huh?

The generation can be explained in three parts.

1: GENERATE A PERLIN NOISE CURVE

A curve, like the one to the left, is a collection of points, which each is defined by the distance and direction to the point behind it. Here, the distance is the same for all points, while the direction gradually changes depending on Perlin noise throughout the curve. Perlin noise is pretty good at creating a mix of tight bends and gentle curves.

However, a curve does not a racetrack make. The two ends of the curve end at:

  1. Different positions
  2. Different angles
Let's fix that.




2: ADJUST FOR ANGULAR AND POSITIONAL DIFFERENCE

We could do something quite complicated to make sure the track would naturally become a circle - or we could just adjust for the two differences.

For instance, like in the above, if there is a 90° difference between beginning and start, we can subtract these 90° throughout the track, so that the first node keeps the same angle, the last node is rotated 90° and the middle one 45° - and so forth.

However, a track of 360° does not necessarily begin and end at the same position. The same method described with angle can be used here, too. Simply shift the nodes throughout the curve so that the ends match.

A note has to be made: Racetracks come in one of two shapes - 360° tracks, which have a circle as base, where cars turn more in one direction than the other - and 0° tracks, where cars turn equally much left and right, which has a figure 8 as base. The current script finds out if the base Perlin noise curve is closer to 0° or 360°, then uses that number to correct for the angle, so that both types of racetracks can be generated. However, this does mean sometimes the smooth morphing shown above jumps suddenly as it switches from 179° rounded down to 0° to 180° rounded up to 360°.



3: RESCALE, RENDER
One weakness with this method is that the racetracks end up with hugely different sizes - especially the very complex shapes tend to become tiny, messed-up balls of track. In the above window, I measure the size of the racetrack, then scales it up as necessary, before drawing onto the screen. This does make the morphing look a bit strange, though.

Rendering is done by iterating through the points of the curve and drawing lines between them, of varying widths and colours - from widest to thinnest: Black, grey, white, grey, and then finally the middle line.

The middle line does not directly adhere to the points of the curve. When the adjustment of position was added, points in the curve no longer remained equidistant. The middle line thus has to go from point to point, a set amount of pixels at a time. Keeping track of this distance, it also switches between white and grey.


Comments