I'm currently working on a terrain mapper, that should do exactly what you want. First of all i pregenerated all transitions between the tiles (so per 2 terrain types there would be 2 tiles for the plain terrain textures and around 12 tiles for the transitions). As the number of needed tiles would grow pretty high, when you have multiple terrains and want to support transitions between all the terrain, the tileset would grow pretty big.
Now currently I'm working on another approach, that in theory (and in my prototype) worked pretty well. I still have to implement it, so the needed tilesets are created on the fly, but this is how I do it:
I have a terrain definition, where all terrain types (for example water, grass, rocks, mountains, desert etc.) are stored. After that I establish an order. I'll explain later, why this order is needed. This order defines, how the different terrain types are related to each other. For example, water is lower than sand (beach), sand is lower than grass, grass is lower than mountains. Therefore you can also say, that water and sand are lower than mountains.
Now I have a special alpha texture, that defines the possible transitions.
Here is the tileset I used in my prototype:
You can see, that you have some terrain textures and an alpha map. I handle the alpha map also as tiles, but they are half sized (terrain textures are 64x64, blend textures are 32x32), this means that every terrain can have up to four blend textures (northwest, northeast, southwest, southeast).
Now basically what you do, when you have a transition is this:
- Draw the ground texture (blends are always applied on the higher terrain types).
- Draw the alpha map with ALPHA_MAP (this only renders the alpha channel)
- Draw the second texture with ALPHA_BLEND (this uses the underlying alpha channel, we rendered out before as alpha for the tile).
So basically this is the theory... But you need to do some things, that it works properly.
What I do is following:
- First generate the level (I use perlin noise, to assign the different terrain types). The output is simply a 2d array containing the terrain types (eg: water, dirt, sand).
- A processor goes through this array and checks for some things and outputs a MappedTileLayer (this is my datastructure, to hold the output). The processor does following:
- Map all terrain types to the according tile in the mapped layer.
- Find tiles, that have neighbours with different (lower) terrain types. If there is a lower neighbour, you also have to render this neighbour terrain underneath actual terrain tile, as otherwise the terrain would just blend to black.
- Based on the neighbours, the correct blend tiles are used. Every terrain type consists of 4 blend tiles. So depending on the existing neighbours, the blend tiles are chosen.
- My renderer renders the tiles on the viewport:
- Render all tiles without any transitions (also render the lowest terrain, where blends will be applied). The tiles rendered in this run can be rendered without the need to apply a blend, as they are the lowest terrain tiles.
- Select first overlay tile (currently there are max 4 overlayes. This is the case, when the tile handled has the highest height in relation to the neighbours and every neighbour is from a different terrain type).
- Render the four blend tiles with ALPHA_MAP
- Render the overlying tile with ALPHA_BLEND
- Repeat this step with the next overlay tile, until there are no tiles left
Like this, you do not have to care about multiple terrain types getting together, as they are rendered from lowest to highest terrain type and the transtitions only concern the higher type.
I know that it is a bit complicated at first, but I currently don't have more graphics, because I'm in the middle of refactoring my source. I will add some graphics representing what I do as soon as possible (also better explaining every step).
I hope this will help you.
One small addition:
My mapper is built, that there is a default blend texture. But you can define specific blend textures for every terrain type. So for example if you want to make smoth transitions for all mappings besides the beach to water transition, you put the smooth transition as default and only set the custom transtition for the beach tiles.
Also, my mapper allows to define multiple transition tiles for each tile type (so if you have a straight edge, you can make multiple blends, so they will alternate).
** Appended **
Because I currently have no assets to show, I created a schematic drawing in paint.net. Keep in mind, I'm a programmer and not and 2d artist, so artistically it is very badly drawn, but it should show, how I tackle the problem with multiple terrain types (>2) coming together). I left out optimizations for simplicity and applying the blending is also not mentioned, as I concentrate on the problem with the multiple terrains.
I will add an example with real textures and blends as soon as I find the time to do so, so this gfx is only temporary.
A explanation to the image I added:
- In the first grid you see the terrain configuration. W stands for water, S for sand and G for grass.
- The second grid shows, how the blend tiles are applied. Like I mentioned earlier, the width and height of the blend tiles is the half of the terrain tiles.
- Here now the first render action happens. The lowest terrain type is water, so we fill all the cells (and all adjacent cells) with the water tiles. So allthough the water tiles only fill the first column of our definition, we have also to fill the second column.
- Now we draw the next layer, but we only draw the tiles, that won't be blended. Water is a lower terrain then sand, so we do not need to expand to that side. But because the grass is higher, we have to fill the adjacent tiles with sand, where the grass blend will be rendered over.
- Now based on some patterns, we render the blending parts of the sand. (Now you see, why we need to also fill the adjacent tiles).
- Here we have repeated steps 4 and 5 (allthough step 4 wouldn't produce any output, as all grass tiles in this examples will contain a blend).
Now you see, in the fourth row in the second column, there is a grass tile. Left of it is a water tile and on top and bottom of it are sand tiles. When we look at the rendering only for this tile, this is what happens:
- The water tile is rendered without a blend.
- The sand tile is rendered with a blend.
- The grass tile is rendered with a blend.
And we could also switch one of the sand tiles and the grass tile on the right to different terrain types, it would still produce correct results.