Sign in to follow this  

Fractal terrain generation on an hexagonal grid

This topic is 827 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone!

 

I'm generating a fractal terrain using Perlin noise for an RTS game, and I want to make it look like the terrain in Civilization V:

[attachment=28955:civ5.jpg]

 

Some of the key features that I want to extract from it are:

  • It has a pointy hexagonal grid.
  • Each grid cell has a possible type: Water, Plains, Hills or Mountain.
  • One grid cell can only have one type.
  • The terrain features are aligned to the grid. You can notice how the mountains are actually centered in their cell, but also affect neighbor cells slightly.
  • It's continuous: You don't get the appearance of white noise in the terrain. There are no small islands spread all around, or mountains in the middle of the ocean. Mountains are usually near hills which are usually near plains.

My current approach is:

  1. I generate a 64x64 Perlin noise texture where each pixel maps to a terrain type: [0, 0.3] is water, (0.3, 0.6] is plains, and so on...
  2. I generate a 256x256 texture by interpolating some points in the middle of the Perlin noise texture using bicubic interpolation, so everything is smoothed out and is continuous even in the first derivative. Then I apply the thresholding for the different terrain types:
    [attachment=28956:landmass.png]
  3. I generate three 256x256 perlin noise textures for the different land types, with different roughness:
    [attachment=28957:terrainfps.png]
  4. I mix these with the landmass texture calculated in step 2, and blend them using linear interpolation. The end result might look something like this, which needs tweaking but is promising:
    [attachment=28958:cartoony_terrain.png]

The problem is: The above procedure works for square-cell grids, but I have an hexagonal grid. I've tried the following approaches, but none worked:

  1. Triangulating the hexagons by making a triangle fan from the center. For the hexagon vertices, I compute the average color of each of the three neighbors that touch it. Problem: It's a linear interpolation, and edges are noticeable in the final result. Also makes it necessary to "guess" the color of the hexagon vertices by calculating that average, which might not be the color we are actually expecting in that point.
  2. Triangulating the hexagonal grid by joining the centers of the hexagons. Problem: It's a linear interpolation again.
  3. Joining 4 hexagon centers into a quad, unskewing it, making a bicubic interpolation and skewing it again. Problem: The terrain looks skewed and not really centerd on the grid cells.
    [sharedmedia=core:attachments:28959]

     

At this point, I'm pretty lost on what else to try to make it look like the one from Civilization V. Any ideas please? Thank you!

Edited by alonso

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

 

May need to refactor your question a bit. As they do solve the problem.

Take a closer look at civilizations terrain. Get really close and look at how it packs in terrain into cells.

Forests, mountain ranges, and massive mountains all fit neatly into their allocated space. Height distances are interpolated between the points, and connected together for the final height map, and resource placement.

 

So try this method first.

Start with the base of a hexagon. Build a world map using the hexagon structure akin to the old DND style.
 

http://www.thekeep.org/~wombat/Greyhawk/abyss_cy589_darlene_map_redo.jpg

From there. Generate your height map on a hex by hex basis using a few rules while having a hex be aware of it's six neighbors.
http://www.redblobgames.com/grids/hexagons/
Here you can figure out how to keep an ID on these grids to avoid using thousands of pointers. You can possibly get away with using a bit field to help you store the Array IDs, and make accessing faster.

Basic Rules.

RULE 1: Fill most of the hex.
RULE 2: meet altitude differenes nearest the edge of the Hex.
RULE 3: Color blendings happens a little ways past the edge.

Generate higher detail displacement maps for mountains. (Remember, we are just going to work on textures here.)

Also keep in mind that Civilization makes heavy use of Adaptive Tesselation to get their terrain effects. It's not a uniform vertex density. And most of their generation processes might take place on the GPU via Compute Shader. So when the GPU is done. It keeps hold of all the needed RGB textures. And will send back a Height map.

 

http://gamma.cs.unc.edu/SDSDA/

 

When I get home. I'll take a look at a practical way to build a terrain system for you.

Edited by Tangletail

Share this post


Link to post
Share on other sites

Ok... this actually wasn't as hard as I have thought. So... I'll give you a hint, and this is how I figured it out.

Draw a Hexagon with all sides being the same length onto a sheet of graphing paper. Draw another at varying sizes.

Find out how the area correlates to each other based on the grid.

Then treat each box as a container of vertices.

 

But now that I think about it, you really don't need to change your tiles to Squares just yet. All the Hexagons are a grid drawn onto a sheet of graphing paper. They have little effect on the underlying system.

Edited by Tangletail

Share this post


Link to post
Share on other sites

Thanks for your replies Tangletail.

 

Regarding your instructions, I actually followed those steps, but:

 

Basic Rules.
RULE 1: Fill most of the hex.
RULE 2: meet altitude differenes nearest the edge of the Hex.
RULE 3: Color blendings happens a little ways past the edge.

 

That's exactly the point where I'm struggling the most. I've tried everything: Barycentric interpolation, triangulating the hexagons, triangulating the grid, making a skewed grid by joining the hexagon centers and using bicubic interpolation there, blurring the hexagonal heightmap, averaging the neighbour hexagons weighted by distance, same averaging but using standard deviation, radial interpolation, and none worked. The latest I tried, which gives the best results but are actually not good (a single cell of water surrounded by land becomes land) is by making a square grid on top of the hexagonal grid like this:

[attachment=29023:squaregrid.png]

Every cell has two known corners (the ones that match the center of the hexagon), and for the other two corners I simply use a cubic interpolation between the adjacent centers horizontally. But it's still not good.

 

I'm now trying another approach, which is building the coastline manually using splines, but it's not giving me the same results as in Civ5 either. The coastline looks ridged.

 

Any hints would be appreciated, I'm going a bit desperate here sad.png

 

Thanks!

Share this post


Link to post
Share on other sites

I'm pretty sure Civ V doesn't generate it's terrain at high detail in the first pass.  Instead, it probably generates the gameplay-specific values per hex (water/plains/hills/mountains, plains/desert/forest, et cetera).  Then for each hex, and for graphical purposes only, it generates the height map.  It would probably be simple enough to generate a circular height map per tile (with radius twice that of the hexagon tiles) and blend each one with the six neighboring meshes.  You'll notice that most hill/mountain tiles have a peak near the center of the tile; they were probably generated as solitary hills/mountains which leveled off to flat ground at the edge of the circle mesh before being blended with any others adjacent to them.

Share this post


Link to post
Share on other sites

I'm pretty sure Civ V doesn't generate it's terrain at high detail in the first pass.  Instead, it probably generates the gameplay-specific values per hex (water/plains/hills/mountains, plains/desert/forest, et cetera).  Then for each hex, and for graphical purposes only, it generates the height map.  It would probably be simple enough to generate a circular height map per tile (with radius twice that of the hexagon tiles) and blend each one with the six neighboring meshes.  You'll notice that most hill/mountain tiles have a peak near the center of the tile; they were probably generated as solitary hills/mountains which leveled off to flat ground at the edge of the circle mesh before being blended with any others adjacent to them.

Hey Andy, thanks! That sounds like a good approach, I'm going to give it a try :)

 

I guess I will also have to find a solution for the coastlines.

Share this post


Link to post
Share on other sites

This topic is 827 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this