Thursday 4 March 2010

Height Maps

Greetings and salutations my friends, I hope you're well! I am in a specially good mood today as I have recently implemented a new feature in my game, and it actually looks cool!

Over the last few days I have been working on a cool way of creating a background for my tower defence game. When speaking with my project supervisor Simon, he mentioned it might be a good idea to create a height map which can be used to render a terrain.

First off, a height map is a way of procedurally generating a graphical scene. The height map itself is basically a grey-scale image (think of clouds) which acts as data that you want your program to get hold of. In order to get hold of the data, you go through the image, taking each pixel in turn, finding the intensity (level of white/black) in each one. The values of each pixel correspond to the heights of your vertices when you go to draw your scene. So white would be the highest point, and black would be the lowest, with all the greys somewhere in between. As you draw your vertices, you go through the list of pixel data and set the height to the corresponding value (you can of course scale this afterwards if you want).

This all sounds perfectly simple and straightforward, and I guess it is compared to some problems you'll face, but as I have come to learn, things are never as simple as they first seem. The first problem I had was getting hold of the actual pixel information itself. I am using SDL to load my images, and while the SDL_Surface object is great, it is not at first blindingly obvious how to get hold of each pixel. Realising I wasn't going to get that working first, I decided to get the drawing code working, and then work out what the height values would be after. Here is what I got first try...


Looks bad I know, instead of finding the height values from the height map image, I randomly set the values between 0 and 100 for each vertex; this was the result. Green probably wasn't the best choice either. At least I knew something was drawing which was a start. I then went about getting the pixel information to work, and I solved it with this little method:

get_pixel(SDL_Surface *surface, int x, int y)
{
Uint8* p = (Uint8*)surface->pixels + 3 * (y * surface->w + x);
return *( Uint16* )p;
}

Here you pass in your SDL_surface that corresponds to the image you have loaded, and the x and y values of the pixel you want to find (the coordinates of the pixel), you next store the pixel information in a pointer to an integer, (the pixel value is stored as an int) and then return it.

Once you have all those values (stored helpfully in a two dimensional array) you simply have to put them into the appropriate place in your drawing code, (which I had finally figured out after several hours of research and bouts of trial and error). I finally got something that looked like this, based on the height map below.


I was skipping and dancing around after I first got this to work. There was no lighting, I was just incrementally increasing the colour from dark to light in each triangle I drew. I then went about getting the lighting code to work, and finally ended up with this:


Success at last! I understand it does kind of obscure the playing area but you get the idea! I have to thank www.videotutorialsrock.com for a lot of information on height maps and techniques on how to create such an effect, I will hopefully be able to move it out of the way of the grid soon too!