Jun 18, 2011

Terrain Generation: Update

Well, I spent a good portion of the last few days working on the terrain generation system and I'm VERY pleased with the results I'm getting now. As is usually the case, what I had thought was a good idea turned out pretty crappy. The perlin noise idea I mentioned in the last post was very difficult to tune to produce interesting results. The image below is pretty much the best I could come up with that didn't look ridiculous:

Image1 "Improved" terrain generation. Note height-based tile selection.

The terrain was taking something like 25 seconds to generate, and looked pretty crappy which wasn't ideal. Around this point I decided to try something crazy, and I was blown away when it immediately produced much better results:

Image2. Crazy idea pays off.

I played around with the code alot at this point, stripping out entire sections, rewriting existing routines, adding totally new stuff and testing lots of new ideas and settings. I spent a good half a day optimising some of the really big number crunching routines and I managed to speed up one of the core routines I was using extensively by a factor of 3, which reduced the terrain generation time to a much nicer 10 or so seconds.

I then spent some time improving the tile selection code to place the different terrain tiles in a smoother fashion. Though I quite liked the "dirty" look of the terrain from a distance, if you zoomed in it looked odd, with tiles appearing to be scattered randomly amongst each other. This was due to the fact that the tile selection was based mostly on the slope of the terrain at that point. The new system uses layers of value noise where each tile type fights it out against the others and the winner is selected. Due to the smooth nature of the value noise function, you get larger regions of the same tile type and there is less oscillation between the different types.

I eventually added 3 additional tile types, a darker version of the grass texture, a rock texture and a pinker sand texture that represents sand dunes. The image below represents the current state of the terrain generator:

Image3. Latest version of the terrain generator.

There's still a fair bit to do, like doing rainfall calculations to generate rivers and lakes, but as I said at the beginning of the post, I'm VERY pleased with the results and wanted to share a better looking screenshot.

Jun 15, 2011

Terrain Generation: A sneak peak :p

I've been working on terrain generation for a few weeks and thought I'd share an early image of the results:

Click image for a larger version.

Since the first scenario I'll be supporting is a desert island, my terrain generation has focussed on islands. The terrain above is about 0.7 square km in size in the game, and is about 300m high at the top of the hill I believe.

I won't go into much detail about the technique in this post, as I'll write up more detailed ones later that go through the full process. However, to build the terrain I generated a Voronoi diagram to produce the shape of the coast, then calculated a signed distance field to produce the heightmap seen above.

In my current dev build I've added perlin noise to rough up the terrain somewhat, and results are looking good.

Jun 1, 2011

Bitmap Fonts

While I haven't written anything about Bulldog in the last 6 weeks. I definitely haven't been idle in the coding/design department.

Following on from my last post about the icon graphics, I've drawn about 15 additional icons for in-game objects. I've also started to put together the user interface, with displays for the player's Health, Energy, Water and Morale stats. I've written alot of additional behind the scenes systems that help hold everything together, but aren't really that interesting in terms of function, so haven't bothered to talk about them in the blog.

However, this past weekend I tackled a feature I've had on the TODO list for quite some time : creating a better font rendering engine. The standard font routines available in SlimDX (or DirectX for that matter) are terrible in both performance and functionality.

The usual way of overcoming this is to produce a bitmap representation of a font at a specific size and then create a system that generates quads for every letter in the text you want to render and apply the individual letter bitmaps to the quads for rendering. I've seen this approach go wrong in some commercial AAA games and produce horrible artifacts at the edge of letters where they've partially overlapped without proper blending, so I decided to try a slightly different approach.

Rather than have a quad for every letter, I create a single big quad for the entire text, and then generate a bitmap of the text to be displayed in memory by placing the letter bitmaps in the appropriate positions, then slap that bitmap onto the quad for rendering. There's some overhead to constructing the text bitmap, but it only needs to be generated once (unless the text changes), and from then on its a single large quad with a texture, which should be much faster than 100's of small quads.

To test the font engine, I created a bitmap font with a hand-drawn appearance, so that it has a comic-like quality to it, but still is quite readable and the letter forms are consistent. The font itself was drawn in Illustrator, then output as a high resolution bitmap, which I then downsampled in Photoshop.

A screenshot from Adobe Illustrator showing the curves used to create the letter shapes.

Creating my own font means it should match in better with the overall graphic style of the game, than if I used a very clean font like Arial. The image below shows the completed font at 22 pixel resolution, which I've called "Olivia22".

The finished "Olivia22" font.

Throwing together the bitmap font engine and drawing the font didn't actually take as long as I thought. The font took about 8 hours to do all 95 glyphs, and the font engine was about the same. The part I was surprised about was how long it took to setup the kerning information for the font.


Kerning

Kerning is the process of adjusting the space between letters in a word to make the characters sit together in an aesthetically pleasing manner. Unless you're involved in graphic design it may not be apparent that a process like kerning is even required. Kerning is typically done with pairs of letters. A "kerning pair" defines the gap between two particular letters, and at render time each letter pair is checked against the list of kerning pairs and the second letter is offset left or right by the appropriate amount.

For overhanging letters such as "W" or "V", kerning is particularly important, especially when paired with letters like "A", or any of the curvy lower case letters, such as "o", "c" or "a". So for my font to "read well" I had to create kerning pairs for problem combinations of letters. The process took many hours of adjusting values, running the program against a reference text and inspecting each word individually. Over the course of 6 hours I put together close to 500 kerning pairs and just about had my eyeballs fall out of their sockets.

The image below is part of the rendered reference text, showing the kerned version of the font. (This is actually from a work in progress, so I've since tweaked some of the pairs to be better).

A crop of part of the rendered reference text


Even after so much work the result is far from perfect. The biggest limitation with the way I've implemented the font renderer is that the smallest distance a letter can be moved left or right is an entire pixel. In many situations, the "correct kerning" is a movement of less than a pixel, so the space can never be correct for that particularly instance. This is less of a problem with larger font sizes, but with the 22 pixel high font I've created, the kerning values are within the range of +3 to -3, which is pretty small, and leads to some compromise.

In an ideal world the font renderer would use the original vector graphics as the source for the letters, and create its own anti-aliased versions at whatever size is required, however I can't be bothered creating such a thing at this stage, especially when I'm trying to hit an end of year deadline. Perhaps in the future?

Another thing which has become apparent is that my process of kerning is time consuming and fiddly. My plan is to create another 3 or so variations on the current font, (ie different sizes and normal/bold versions). If its going to be 6 hours of kerning for every one of those I'll go insane. So I've come up with an improved workflow for kerning that should shave hours off the time.

The current workflow involves setting the kerning values in the font's data file, running the test code that takes the reference text and produces an output png of the rendered text, loading the png in photoshop and looking over the entire text to spot problems and then repeating the entire process.

The improved workflow relies on me getting the TextBox control working, and adding the ability to tweak the kerning per character pair directly in the text using the cursor keys. This should greatly speed up the process, as the kerning changes will be visible immediately, and without having to load the output in an external application.