Advertisement

Some doubts regarding hex grid terrains like CIV5/6 or AOW.

Started by January 15, 2020 12:24 AM
9 comments, last by Devem 4 years, 2 months ago

Hello!

I have started a small project with the intention of building a terrain generator / editor in order to create terrains similar to those founds in games like CIV5/6 or Age Of Wonders to name a few of the big ones (albeit simpler than those of course). Below I provide some images to serve as reference of the type of terrains I'm aiming to reproduce, specially the second one which is the closes to the kind of look I'm trying to achieve albeit in a much smaller scale :

CIV5

Unity of Command 2

Panzer Corps 2

My current approach to the problem of generating the terrain is as follow:

1 - First, we generate a hexagonal grid following the theory from RedBlobGames. Store the hexagons data (ID, vertices and anything else that may be necessary) and create a single mesh comprised of hexagonal cells, similar to the one created by CatLikeCoding at the beggining of the first chapter. (i.e the actual terrain mesh has an hexagon pattern). This is the point I'm doubtful about, more at the end.

2 - Depending on whether we are procedurally generating the world or editing it by hand, use a noise function or user input to create a texture where we store, for each hexagon ID, the type of terrain (plane, hill, forest, mountain, shore, ….).

3 - Now, for each cell in the grid two operations are necessary. First, depending on the type of terrain (plain, hill, mountain, …) add extra triangulation to the hexagon so it has enough triangles to accurately represent the terrain characteristics. I believe one could be more fancy and use tesellation or other techniques to provide better results but I will keep it simple and optimize later, furthermore I'm completly ignorant of how tesellation actually works so I will stay away from it for now. ?

4 - Afterwards, once all hexagons have been triangulated with extra triangles if it was necessary, I will use procedural generated heightmaps to create the shapes of the mountains or whatever other kind of terrain I'm trying to simulate.

5 - For things like rivers or roads, I feel I will try to generate them with curves and directly modify the terrain mesh in order to place them on it. Think of something similar to what is done in city builder games. I believe this can be a bit troublesome but right now I'm not too worried about it and I feel this approach will work quite well.

While I believe I have more or less a direction to move on there are some doubts I wasn't able to find on the Internet regarding the concept of hex meshes for terrain generation of hex grids games. Let me explain myself:

In step 1, I generate a mesh with an hexagon pattern for the terrain (like this). Do games as the ones I provided above really have an hexagonal pattern mesh (with lots more of extra triangles of course) as their terrain mesh?

As far as I see it, it could be possible to create a simpler quad mesh and then, “hexagons” (which wouldn't really exist in the mesh but instead only logically) would store all the vertices that are inside their area and influence them when creating whatever terrain the hexagon would contain. This quad mesh wouldn't adapt well for games where the terrain is quite stylized and hexes are cleary visible (as the example from CatLikeCoding is) but seems pretty good for games like CIV where the hexagons are quite hidden.

Of course, this method would give some issues for actually showing an hexagonal grid over the terrain as it would have dissapeared completely from it. Instead, a decal projection could be used to show the grid over all the terrain (as in this image) and, for cases like borders or areas of movements a second simple hex like mesh could be used for them combined with a little bit of shader trickery, maybe as a postfx rendering the area to a mask or something else, like this, or this one or this final one which wouldn't be a an pure hex.

Am I correct to think that there is no need to actually instantiate a hex-patterned mesh if my objective is to achieve a more “realistic” looking terrain and the correct solution would be to instead use a simple quad mesh for the terrain below?

Thank you very much,

Sorry for the wall of text and hopefully I made myself quite clear ?.

What ever you do, do not re sample the hex mesh as a quad mesh. I mean quads with 90 degree angles. If you skew your quads to meet the xy coords of the hex, you may be able to resuse some code.

I am thinking of CLOD. You are thinking of generation. I do not touch this heuristic generation libraries, so I will probably have to re-sample from quads to hex. Maybe you can decide on a style of your game and adapt a small code snippet for mountains. If you use 2d FFT in the process, then yes you may have to resample. Or use ansitrophic envelope in Fourier-Space? I am pretty sure you can use the Fourierer series to produce a periodic terrain with hex tiles.

Advertisement

I will take a look at FFTs once I start working on mountain generations. For now I have decided to keep my hex patterned mesh as it fits better with the kind of gameplay and editor tools based on an hex grid terrain I have in mind. Sadly, I have not been able to work much this days but I will try to update this post once I have something of substance to show.

Thanks for the answer!

Tiled hexagons have a really useful property - they are the dual graph of tiled triangles (i.e. the triangle midpoints are the vertices of the hexagons, and vice-versa):

Hegagon and triangle dual meshes overlaid

You can often exploit this fact to use a regular triangle mesh for all your typical graphics operations, but use the hexagon grid for generating the data and gameplay. For example, like this procedural planet generator does.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Devem said:
Am I correct to think that there is no need to actually instantiate a hex-patterned mesh if my objective is to achieve a more “realistic” looking terrain and the correct solution would be to instead use a simple quad mesh for the terrain below?

Correct, the hexagonal grid matters most for gameplay and logic, but otherwise you can chose any visual representation you'd like for the terrain, quad mesh or otherwise. It makes sense if it has features that roughly follow the underlying grid shape so the player knows what's going on, but that's entirely up to the art direction of your game. Take the Panzer Corps 2 screenshot you linked for example, if you remove the UI overlays you'd be hard pressed to tell it's a hex-based game based on the terrain alone.

It's worth noting that the heavier reliance on UI and other visual overlays in these types of games, is what allows the artists more freedom in designing terrain that doesn't need to have those queues built-in.

Put a vertex in the center of each hex, and each hex becomes six triangles. Each triangle can be recursively subdivided, multiplying the number of triangles by four at each step. This gives you a triangle mesh that's objectively better than the typical square-based quad mesh:

  • It's already in triangles, so you don't need a separate triangulation pass.
  • It's already in triangles, so there is no ambiguity about how the quads should be split into triangles.
  • The triangles are less elongated, which improves rendering performance.
  • The mesh just looks better at low resolutions.

So, while you could a quad-based mesh for rendering, why would you want to?

Advertisement

You split the hex into 6 triangles? In same way you could split a quad into 4 triangles from its center, which is basically the same process (you additionally have the choice of only using 2).

Obviously it's possible (easy even) to split quads into triangles, but if the quads are squares, you're going to get ugly isosceles right triangles whereas if you start with a regular hexagon you can get beautiful equilateral triangles. For that matter, you could split a hexagon into three non-square quads by adding a vertex in the center but only creating three (evenly spaced) edges from the central vertex to the perimeter vertices, or into two non-square quads by simply splitting the hexagon straight down the middle from one vertex to another. You could even split the hexagon into four triangles by splitting first into two quads, then splitting each quad to form two rectangles.

There is nothing challenging or interesting about being able to split arbitrary polygons into arbitrary smaller polygons. The tricky bit is splitting polygons while keeping the resulting triangles as close to equilateral as possible. Starting from regular hexagons allows you to get perfect equilateral triangles (minus any distortion applied by adding elevation). Starting from squares does not.

SwiftCoder's got the big element right there.

As you already linked, a hex world can easily be represented as a regular grid in game data. Regular grids are easy, just a rectangular array. In a hex world each row or column of the grid is staggered, but the data is still just a rectangular array.

The graphics for the hex world are composed of continuous blocks. Many games tile the individual hexes, other games create transition tiles for the triangles as SwiftCoder demonstrated. It takes more art effort as the number of combinations increase, but the tech behind it is easy enough, rotate the triangle until it matches. You can even couple the two, with a Civ-like world with suitable triangles for the terrain, overlaid with suitable hexagons or other objects on the terrain.

It is much harder to work with an arbitrary world mesh or arbitrary map and then overlay the hex world on top of it. While they certainly may exist and I don't have encyclopedic knowledge there, I don't know of any hex-based game that went with that approach. I do know of hundreds of games that went with the triangle map as SwiftCoder described, and with the hex encodings linked to in the original post; both of those are popular and common, having been used since the 1980s when they were popularized with D&D hex maps and similar games.

Hello everybody. Sorry for the necroing but between working in another project for a friend, researching other topics and work related issues I totally forgot about following this thread.

During this time I decided to leave the hexagon terrain on hold and keep developing other topics that would allow me to get a better picture of how to solve this problem (procedural generation algorithms for map generation, LOD approaches both static or CLOD algorithms, terrain texturing through unique textures or splatmaps, …). Below I leave my thoughts of the things that I have been learning in case somebody might find them useful. Note that these are my opinions and they may not be completely right! Wall of text ahead!

When developing a terrain one should first start by considering two different things: artistic style (low poly like Second Front or “realistic” like CIV or Panzer Generals) and the view distance and camera angle (can we put the camera close to the ground and see far away or is the camera "locked" like in games like CIV where we are stuck with an almost cenital perspective).

With low poly terrains, the best approach is to simply make the mesh follow an hexagonal topoly as it was done in the OP. That way code can be easily made to modify the vertices and add any extrusion or insets to generate the final terrain look for each tile. An example of this is the Catlike Coding Hex Map tutorials . This also allows for easy modification of uv coordinates and vertex colors to keep each tile visually distinct from the rest, which tends to be the case in low poly styles.

For the realistic style I would not recommend the use of an hexagonal topology for the graphical aspect let me explain below why:

Your hexagonal grid should not exist as a mesh but only as data as was said by frob. You keep each tile and all it's data (position, terrain type, neighbors, …) stored in memory and use it to generate the final terrain.

To create the terrain you will generate a terrain heightmap and a way to texture it (this could be done with a splatmap shader which some constraints or with a unique texture per terrain chunk but I won't delve into too much detail, if you don't know what these things are, look them up before working on this).

A good approach for the terrain generation is the one approached here: https://www.reddit.com/r/gamedev/comments/7372p2/how_to_texture_a_procedurally_generated_mesh/​ where the terrain heightmap is generated by rendering planes above the hexagons positions with height brushes for each tile into a texture that is used as heightmap for the given chunk. (The guy in this post ended up using Compute Shaders to generate these textures due to finding the whole process quite slow).

For the rendering of the terrain, use a normal mesh comprised of quads in which you apply the heightmap and your textures. Something like the slide 10 of this CIV5 presentation. Then, you can apply mesh simplification algorithms like Fast Quadric Simplification or a Quadtree Tesellation to reduce the details in flat areas and keep it where it's needed and even use hardware tessellation to add extra details with the GPU when approaching mountains or other highly detailed terrains. The devs of CIV seemed to use a custom tessellation algorithm being run by a CS to generate the mesh but I believe that approach might be quite hard to start with.

The good thing about using a quad mesh for terrain rendering is that it also allows the application of CLOD algorithms like Geomipmapping or Chunked LODS to allow for long viewing distances in all directions while keeping your vertex count controled if you want your game's camera to be able to look into the horizon.

I ended up discarding tessellating hexagons directly due to a simple issue I didn't think about when I first started. Each time you add extra triangles to an hexagons, you must be sure the vertices a the edges between triangles are kept aligned to avoid cracks in the final mesh. You can prevent this by forcing edge vertices to be all at the same height always or by adding a skirt between hexes, but I found the solution to be a bit ugly.

Hopefully, this may help somebody!

Thanks to everybody who replied ?

This topic is closed to new replies.

Advertisement