Any support through donation is greatly appreciated!
You don't need a PayPal account to donate.

June 4, 2009

Procedural Generation 2

Today on the menu: heightmaps, and applying mathematical curves to optimize them!

Well, I got inspired to mess around with some more procedurally-generated land again. This time, I tried going at it with a heightmap. After one faulty attempt, I came to a satisfying result. The heightmap allows me to choose a "roughness" constant between 0 and 1, 1 being very smooth and 0 being very rough. I decide to default this at about 0.7, and generate my first heightmap:



The method of creating a heightmap is fairly similar to the method I used in my previous post about map generation, because they are both fractal methods. In both, you start at a large scale, and then at each iteration you half the scale at which you are operating, until you are working with each pixel individually. But a heightmap is a bit different: our goal is actually to create a map of different heights which smoothly transition between each other -- like in my cloudy image above.

The approach to this is simple. You start by placing a single height point, at the top-left of the map. We then use a method called Midpoint Displacement to value all the nodes between the ones we've already valued, giving them a value that is an average of the surrounding points, with a slight random factor to vary the terrain. I won't go into explaining more, but I recommend the diamond-square algorithm that is taught in the tutorial I just linked to.

My GML interpretation of the code is here, if you want to see it: midpoint.txt

Now the tricky part -- how am I supposed to turn this into land? The greyscale represents a value from 0 to 100 for each pixel, but right now it just looks like fuzz. So I figured first thing I needed to do was set a water level. I set this at 50, so it'll cut the heightmap right in half hopefully. Then, I have the hue of each pixel range closer to blue or green, depending on whether it is above or below the water level, and by how much.

I generated another, and this is what I got:



I liked the way the colors transition, but there's a problem with this. It's still too "cloudy" looking. I don't want to just split the colors immediately, so it looks too pixelly, but rather I want the water to transition smoothly into land. I realize that my problem is that the transition from water -> land is too shallow, I need to steepen it.

So I first create a function that curves the value as it approaches 1 (using a quadradic, then inversing it after 0.5), so the value climb was originally like the red line in the graph below, but now all the values are being fitted onto the blue line:



This works wonderfully! now, the deeper parts of the water are made even deeper, yet it still approaches the water level at the same point, and the land flattens out more. As a result, the actually transition from water -> land (the middle area of the graph) is a lot steeper. My maps generate something like this now (a non-colored generation is also shown, the settings were the exact same for both of these):



It's still a bit fuzzy, but now I've worked out the solution; all I have to do is find the curve that fits. After experimenting with a cubic, sin, exponential, and a circular curve, I wrote a function that allows me to switch which curve I am using after the water-level has been passed. So if you have a look at the graph below...



The blue and green are the water and land respectively. If I choose the red curve, I end up with much more water than land, and the water is deep and wide while the land is very tall, like cliffs. This works if I want lots of islands, like so:



If I choose the pink curve, I get the exact opposite. If I choose any of the middle curves, I have many more options; because they all meet at the same point (water-level), I can actually use one curve underwater, and then another curve after I'm above the water. In the map below, I used the orange curve combined with the purple (which, in my crappy graph, are supposed to represent an exponential and a quadratic curve):



The below is an exponential curve going into the linear rise (blue curve). In this one, I also set the water level down a bit, and increased the roughness value of the heightmap, to break up the land a bit and spread it out:



If you ask me, that last one looks a lot better than the first colored one in this post. I was quite happy with how everything worked out.

3 Comments:

Blogger James K. said...

in my laman way of thinking, it seems like the closer you are to your goal, the more it looks like a real satellite view of the earth, huh, huh? Especially the last picture.
nice job!

June 04, 2009  
Anonymous Anonymous said...

Those last ones are beautiful. Both of your posts have been really fascinating. Would you be willing to post the gml for the last couple with the exponential/quadratic curves?

June 04, 2009  
Blogger HandCraftedRadio said...

That is really awesome, those maps look really good. I really enjoyed reading this article and the first one, thanks for writing these up! You have inspired me to want to try some procedural generation stuff.

June 18, 2009  

Post a Comment

<< Home

Site graphics and design © 2009, Chevy Johnston