Content Generation for Programmers Pt1

One of the key challenges facing budding new game programmers is getting artwork. You may have the greatest game concept ever conceived but without an ability to demonstrate it visually that is all it shall remain. The options available to one man band outfits (such as myself) are:

  1. Find an artist to do it for you.
  2. Find a source of free artwork.
  3. Hope blue rectangles and red circles will hold up.
  4. Steal artwork from an existing game.
  5. Learn how to do it yourself.

This article will focus on option 5, which is not quite as difficult as you might imagine. It is actually reasonably easy to produce quality artwork in a short period of time if you limit yourself to producing the type of artwork that can be done quickly and easily. The main limitation you will face is animation. Animation is hard. Animation is really hard. You can’t fake animation, you can’t have rough animations that look pretty good. Animation is something that unless done really well, looks really bad. So basically, don’t do animation. This does cut down your options in the genre of game you can produce quite considerably, but hey creativity thrives when constrained. So basically go for something with blocks, balls, cars, planes, boats etc.

Ok, so on to how to do it. In part one of this article I will go over a quick way to produce nice looking artwork without going near a paint program. In part two I will go over how to make a nice looking vehicle graphics with minimal artistic talent.

Procedural content generation has many advantages especially for programmers. It doesn’t involve paint programs. It considerably reduces the size of the game. If done right it can look very professional. So without further ado, here is how the planets in StrafeFighter were done.

Step 1, Make some noise.

At it’s heart Procedural content generation is random. So first things first we need a source of randomness. This is actually much harder than you might imagine. Lets start with Math.random() that is pretty random, random looks like this:


Sourcecode:

int size = 256;
BufferedImage img = new BufferedImage(size,size, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < size; x++){
for(int y = 0; y < size; y++){
float val = (float)Math.random();
int rgb = Color.HSBtoRGB(0.0f,0.0f,val);
img.setRGB(x, y, rgb);
}
}

Which is not particularly exciting. What we want is something that is not quite so random. Getting something not quite random and fast is actually pretty tricky. Luckily a guy by the name of Ken Perlin has already solved this problem for you and has come up with pretty much the ultimate noise function, Perlin noise. And if that wasn’t enough he went ahead and came up with an even better one than that, Simplex noise. Simplex noise looks pretty similar to Perlin and has less complicated code (although it is conceptually harder to understand) and is significantly faster for higher dimensions. I recommend this article: http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf. It has a pretty good explanation and Java source code. Here is what basic Simplex noise looks like:

Simplex Noise

int size = 256;
int radius = size/2;
BufferedImage img = new BufferedImage(size,size, BufferedImage.TYPE_INT_ARGB)
for(int x = 0; x < img.getWidth(); x++){
for(int y = 0; y < img.getHeight(); y++){
float dx = (x - radius)/(float)radius;  // normalized coordinates -1 -> 1 from left to right
float dy = (y - radius)/(float)radius;  // normalized coordinates -1 -> 1 from top to bottom
// Set every pixel in the image to random value.
float val = function.eval(dx,dy);
int rgb = Color.HSBtoRGB(0.0f,0.0f,val);
img.setRGB(x, y, rgb);
}
}

This is starting to look interesting. Now you may be wondering looking at the above code what the function object is. At this point is worth introducing a very powerful interface for generating procedural content.

public interface Function2D {
float eval(float x, float y);
}

The function object is an instance of a class which implements this interface using a Simplex noise generator. We will see later on how defining this very simple interface allows a great deal of flexibility.

You will notice that the texture is looking a little bit smooth and lacks any detail. The easiest way to get some nice details is to add in some higher frequency noise to it. You do this by simply adding a smaller and smaller amounts of at noise generated with increasingly extreme coordinates. Luckily it is really easy do do using the Function2D interface:

public class Fractal implements Function2D {

private Function2D source;
private int octaves;
private float fade;

public Fractal(Function2D source, int octaves, float fade) {
this.source = source;
this.octaves = octaves;
this.fade = fade;
}

public float eval(float x, float y) {
float sum = 0;
float curWeight = 1.0f;
for(int i = 0; i < octaves;i++){
// The bit shifts are just a way to quickly get the i'th power of 2.
sum += curWeight*source.eval(x*(1<<i),y*(1<<i));
curWeight *= fade;
}
return sum;
}
}

I have called it Fractal because it shares many properties with them and is actually an implementation of something called Fractional Brownian Motion. Octaves basically says how many times we run the source function and fade describes how much of the result we add at each iteration. Now if we construct a Fractal passing it a Simplex noise source the result looks like this:

Simplex Noise
Now were talking. But it’s all gray, we need some colour. Now at the moment we are generating a noise value for each pixel and setting the brightness of that pixel to that value. One way of generating nice colourful images is to use the random value as an index into a colour table rather than for the brightness of the pixel. A nice way of generating a colour table is just to fire up a paint program (I know I said no paint programs but this is an exception) and go nuts with the gradient tool. Gimp is my preferred program (it’s free) and has some really nice preset gradients. For an earth-like planet I went with this one.

Simplex Noise

Which results in:

Square Earth

Ok so this is looking pretty nice, but it is square, we need round planets. Well this is pretty easy, let’s just set the pixels outside of a circle to be transparent (when dx*dx + dy*dy > 1). and hey presto:

Round Earth

Hmm… this is looking circular but planets are spherical. Well after playing around with a few ways of distorting the texture to make it look spherical I found the best way was using an elliptic lens. This ends up look like the following:

Sphere Earth

To do this, take the normalized coordinates you would have used to evaluate the fractal function and run them through this first:

void distort(float x, float y, Vector2D dest) {
float z;
float tmp, rx, ry;
float ri = 0.5f; // refraction index

z = (float)Math.sqrt(1 - x * x  - y * y);

rx = ri * x;
tmp = (float)Math.sqrt(1 - rx * rx - y * y);
dest.x = rx * (1 - y * y) / (z * tmp + rx * x);

ry = ri * y;
tmp = (float)Math.sqrt(1 - x * x - ry * ry);
dest.y = ry * (1 - x * x) / (z * tmp + ry * y);
}

And thats pretty much it. We can add a nice atmosphere simply by adding a blue colour and fading the alpha value to zero as we go out. Diffusely lighting a sphere is also pretty easy we just multiply each pixels brightness by a light value calculated with:

light = (lightPos.x*dx + lightPos.y*dy)*DIFFUSE_LIGHT + AMBIENT_LIGHT;

lightPos is a vector that is the direction of the light relative to the planet. AMBIENT_LIGHT and DIFFUSE light can be used to control the relative lighting across the planet between the dark/light side. The end result looks like this:

Final Earth

The great thing about the Function2D interface is it is really easy to cascade function blocks to get just about any planet you can imagine. The following Gas Giant was generated using

Function jupiter = new Adder(new Scaler(0.05f, 1.0f,
new Fractal(new Simplex(0),6, 0.5f)), 0.9f,
new Scaler(2.0f, 2.0f, new Fractal(new Simplex(0),8, 0.7f)), 0.1f);

The Adder and Scalar classes are implementations of Function2D that add or scale other functions. The two parameters for scalar are the x scale and y scale.  The adder parameters are the weights of the first and section functions.

Jupiter

Procedural content generation is a powerful technique particularly useful for the artistically inept. Although it is great for backgrounds and textured simple shapes it is really pretty difficult to procedurally generate a car. So for part 2 (coming soon) I will go over some techniques for drawing (gasp) mechanical things like ships and vehicles.

5 Responses to “Content Generation for Programmers Pt1”

  1. moogie Says:

    nice tutorial! good effort

  2. rob Says:

    very nice tutorial. need more stuff ;)

  3. herzal Says:

    nice tutorial, can’t wait for pt. 2

  4. Anonymous Says:

    It’s fractional brownian motion

  5. admin Says:

    Well spotted, thanks.

Leave a Reply