Wednesday, March 27, 2019

Better basins

Although the endorheic lakes are working fairly well, I wasn't really happy with the river networks around them, even on those occasions when there weren't any bugs:


While there aren't exactly any problems with this map, I think the drainage area for this lake should be wider. Endorheic lakes typically appear in the middle of large arid areas where all the water flows to a central point. So those other rivers that pass fairly close to this lake, but flow past it and ultimately into the sea, look a little odd.

As described in the previous post, endorheic lakes are made in two stages. First, during the river calculation stage, we place small areas of sea at random points where rivers are flowing through deserts. We also adjust the flow directions of the surrounding cells to ensure that they are all flowing into these patches of sea. Second, after all the rivers have been done, these small seas are turned into proper lakes. But a lot of the problems I've been having have been associated with the redirection of rivers into lakes. So it occurred to me: why not create those small areas of sea before any rivers have been placed at all? Moreover, what if, at that same stage, we alter the shape of the land for quite a way around to ensure that all the rivers naturally flow into that patch of sea, during the river calculation phase, without having to be artificially routed into it?

So I tried this. First, the program creates those small areas of sea after the precipitation has been calculated (so it knows to put them in dry areas) but before any rivers have been calculated. Then we have a new routine to create a depression around each one. It's pretty simple: it moves outwards from the lake in a series of concentric circles, each time checking to see whether the elevation of each cell in that ring is higher than a set amount. Any cell that is too high is lowered to that set amount. Each time the circle widens, the set amount is raised a little. The program goes outward from the sea, slowly raising the maximum elevation, until no cells need to be lowered, and then it stops. The effect is as if an enormous saucer were gently pressed into the land around the lake, creating a wide bowl-like depression in which any rivers will naturally run into the lake at the centre. And then, as before, once all the rivers are done our patches of sea are turned into salt lakes. However, they are made much lower in elevation than they were before, so they sit nicely at the bottom of their basins.

I found that making the basins this way tended to result in rather straight rivers running down them, so I added some variation in the heights as the basins are made - and then had it do the Planchon-Darboux algorithm yet again, to ensure that no new depressions were created within the basins (other than the one at the centre, of course, which we actually want).

This gets us global river maps like this:


You can see (hopefully) that some of those isolated lakes have got quite extensive systems of rivers draining into them, like spiders sitting in the middle of large webs.

However, this did cause some annoying problems (of course) at the regional level. Some rivers stopped just short of the lakes, like this:


I think that this was because, when creating the rivers at the global level, UW was unable to run these ones on for some cells into the sea, as it normally does, because the sea was so small. At the regional level, the rivers therefore stop when they reach (what was originally) the sea tile, but because the coastline of the lake doesn't map perfectly onto the boundary between tiles, it may not reach the actual lake. (This is just a guess. It may be caused by something else entirely. Who knows?)

I spent quite a lot of time trying to rectify this, either by tinkering with the global river calculation or by adding a routine at the regional level to detect these unfinished rivers and finish them. Eventually I went with a solution of the latter kind, but it's a real bodge job. It ought to detect the nearest lake or sea cell and create new river directly to it, but for some reason this just won't work. So now it just continues the river in the direction it was originally going in until it hits lake or sea. This isn't really ideal, because perhaps it wasn't going in a direction that would hit lake or sea (although you'd think it would usually be). Still, this bodge works for now, and perhaps I'll be able to see what's wrong with the superior method when I'm less tired.

So now I'm getting salt lakes like these (both relief and river maps, for clarity's sake):



I like this one, where a couple of the rivers flow through a rift lake and then subsequently drain into a salt lake:



There is another issue. Previously, we could guarantee that any endorheic lake would have at least one river flowing into it, because they were created on rivers during the river calculation phase. With this new method, the lakes are placed before any rivers have been done at all, so there's always a chance that no river will flow into the lake, even with the wide basin around it. Since it's being placed in a desert, this may be quite probable. That's not ideal. However, it's not much of a problem, thanks to the lake precipitation effect. If there is any prevailing wind over the lake, it will cause some precipitation to occur nearby, and that should result in at least some small rivers, which our nice basin will cause to flow back into the lake. Here's an example of a lake that's affecting the local climate:


And here's the river map, showing the rivers in that patch of milder climate:


I rather like this, as the lake has its own complete, self-contained hydrological system going on there.

Of course, if the lake is somewhere without any prevailing winds (such as the horse latitudes, which are associated with deserts after all), this precipitation effect won't occur and so these rivers won't form either. But that doesn't happen tremendously often, and I don't think it's a huge problem - after all, desert rivers are pretty unreliable. Perhaps endorheic lakes with no inflows at all are just on the verge of drying up.

Now all of this raises the question: what about freshwater lakes? Could I adapt this basin-carving method to those, so that they too have wide drainage areas with rivers flowing naturally into them, avoiding all the messing about with river redirection that they currently involve? It's not as straightforward as it might seem. This new method of doing the salt lakes involves placing them at a low elevation - lower than the surrounding terrain - and then carving that surrounding terrain into a saucerlike depression around the lakes. But freshwater lakes need to have outflows. That means they can't be lower than all of the surrounding terrain. They must, in fact, be at the elevation of the outflowing river, which itself must then drop in elevation as it moves away from the lake.

Suppose we try the following. After the precipitation calculations, but before the river calculations, we pick random spots that aren't in deserts (these will certainly have rivers running through them of some size or another). We then use a lake template to flatten an area around the starting spot, such that any cells that are higher are lowered to be the same elevation as the starting spot, but any cells that are lower are left alone. Because of Planchon-Darboux, every area on the map has at least a gentle slope, so that should effectively mean that our starting spot now has a flattened area cut into the hillside above it. Then we run our basin routine around this spot. This again will affect the area upslope of our starting point. Then we run Planchon-Darboux again (well, we're already running it after creating the endorheic basins, so we'll just do the freshwater basins before that point so it captures them too). This should result in the flattened area becoming a gentle slope. Now, when we do the river calculations, any rivers within the catchment area of the basin should hopefully run down into it, meet, and flow out naturally as a single river from the starting spot down the slope that was already there. Finally, we place our lake over the flattened area in the normal way.

That gets us lakes like this:


It hasn't really worked. The lake has multiple outflows and its catchment area doesn't seem to be very wide. If the original selected point was on only a relatively shallow slope, then the basin carving won't have had much effect, and there might be multiple lake cells that are low enough to have rivers flowing out of them.

So we need to tinker further with the routine. What if we change it so that the basin is carved not merely by lowering cells that are too high, but by also raising cells that are too low? In other words, we don't simply press a giant saucer down on the terrain - we build one up on top of it. That way, we can guarantee a wide catchment area and also avoid multiple outflows. But we still want one outflowing river: how will that escape from the lake? Simple: we create an array and mark on that array all the cells downstream of our starting lake cell. Then, when we create the basin, we avoid messing with any cells that are marked on that array. That should ensure a path for one - and only one - river to leave the lake.

Trying that, I get the following world map:


Looks like I need to add a line stopping the basins from appearing over the sea. Also, of course, the basins rise up gradually as they get further from the central lake - and then they stop, leaving a sharp cliff edge down, so we have these enormous disc-like structures all over the place, rather like Venusian pancake domes. And, last of all, there's something wrong with the slopes of the basins - they're not directing the rivers towards the lakes:


So that was pretty comprehensively wrong. Let's try correcting some of these problems. Instructing the program not to create basins over seas is easy. Getting the slopes to work properly is harder. I tried increasing the steepness of the slopes, but that didn't help:


The whole basin is getting raised more than it should - you can see that the land is uniformly high right up to the shores of the lakes. I think the problem is the depression-filling algorithm. Marking out the path of the outflowing river doesn't seem to be stopping the algorithm from filling the basin up as if it's an unwanted depression. I try making that path wider, but it doesn't help.

After some time, my stupidity becomes apparent. All of this is being done before the flow directions are calculated. But when I mark the cells downstream of the outflow, I'm relying on the flow directions. So that isn't working. So when the basins are created, they don't leave any route for an outflow at all. So the depression-filling routine just fills the basins up completely.

So! I write a new routine to mark the downstream cells that doesn't rely on pre-calculated flow directions, but works them out on the hop. Now we have lakes like this:


You can see the raised basin there quite clearly - the edges are still sharp, so I will need to do something about that. The river map of this region shows the lake's catchment area even more clearly:


But by some miracle it does seem to be working. All the rivers in that area are flowing straight into our lake, except for the one that's flowing out of it, to the north.

I find similar patterns around other lakes. However, some have more than one outflow, which shouldn't be happening. I wonder whether this is somehow caused by the variations in the basin-creating routine. I change it so that the basins are smooth, and move the freshwater lake basin routine to be after the depression-filling routine associated with the salt lake basins. This doesn't help much - I'm still getting lakes like this one (which admittedly looks pretty cool, but surely isn't realistic):


There are also issues like this:


Look at all those rivers running to the lake through the mountains. The basin is created in such a way that mountains are basically ignored (remember, rivers are calculated on the basis of the underlying elevation, not the mountains themselves), and so we get unrealistic results like that. There are also some strange and annoying artefacts here: the outflowing river from this lake has turned into an estuary all the way along, and there are some really odd sections of sea disconnected from the main ocean, near the coasts. I'm not sure why. Parts of the coastline itself look too straight and blocky. I think that this last issue is caused by the high ground of the basin being near the coast, which forces the diamond-square routine to create less variation when working out the coastlines.

My conclusion: trying to do freshwater lakes using the basins method is just more trouble than it's worth. The existing method does more or less work most of the time, so I'll stick with that, at least for now. Which means that the second half of this post was basically a waste of time... but at least I gave it a try!

Friday, March 22, 2019

Getting salty

Well, over the past week or two I've been developing a quite different method of generating lakes at the global level, to avoid a lot of the problems associated with the current method. It didn't work, so I'm just sticking with what I've got.

That means it's time for yet another kind of lake!

I want to add endorheic lakes to Undiscovered Worlds. These are lakes that have no outflow. Although they have rivers flowing into them, they do not overflow because they lose enough water through evaporation to remain more or less static. So these lakes are only found in hot, arid locations, and they tend to be very salty, because the minerals in the water cannot escape to the sea. Famous examples include the Great Salt Lake in the US and the Dead Sea, and arguably the Caspian Sea, although the latter is anomalous in various ways (it is, in a sense, half lake and half sea).

Lakes of this kind are more common than one might think; Wikipedia claims that about 18% of the world's land surface is within the watershed of endorheic lakes. So we definitely want them in our worlds.

Fortunately it's not tremendously hard to do - in theory. All I have to do is add some variables to the existing global lake generating routine so that it can generate lakes in desert regions too (previously, they were not allowed). Such lakes will (a) be relatively small, and (b) have no outflows, making them less problematic to generate. Moreover, we'll have a new global array which will hold information about unusual terrain features (I'll call it "specials"). A certain value on that array will indicate that the lake is salty.

A bit of grappling with the routine, and we get lakes like this:


I think that looks reasonable. (Notice the strong lake precipitation effect here - the winds are easterly at this point - the result is actually some rainforest to the west of the lake.)

Checking the river map for this region reveals:


And what a surprise - we have some problems.

First, there seems to be a river coming out of the lake to the west. How can such a river exist, when the lake-creating routine is supposed to ensure that all rivers on or next to the lake are flowing into it?

Second, and more seriously, there are some very weird things going on with other rivers in this region. To the north and northeast of the lake there are some points where rivers start flowing in tight, knot-like circles and don't go anywhere. This is something I've never seen before. What could possibly be causing this?

Well, regenerating everything without salt lakes removes those weird river knots, so it's certainly being caused by the lake. Moreover, doing it all again with the salt lakes, but allowing the river inflows and outflows to be calculated normally, also removes them:


So there's something wrong with the way I'm altering the river calculations with these lakes. I'm trying to be clever and adapting the river generation function so that, for salt lakes, it doesn't calculate an outflowing river in the first place, but evidently it's not working properly. An alternative is to allow the function to calculate it, just as for a normal lake, but then simply delete the outflow afterwards. Unfortunately, that simply doesn't work. After a lot of attempts (slow, because I have to regenerate the whole world every time), I can't find a way to do it that doesn't have awful knock-on effects on nearby rivers.

So I try a completely different approach. This time, I try placing the salt lakes during the river calculation phase. While tracing the drops that calculate the amount of flow on each cell, I put in a check to see (a) whether this is the first drop to pass over that cell, and (b) whether it's the right temperature/aridity for a salt lake. If so, there is random chance of creating not a lake but sea at that cell (and at surrounding cells, following a standard lake template). The routine also ensures that the flow direction on any neighbouring cells is into the new patch of sea. That means that it will be taken into account when tracing subsequent drops: if they flow into this patch of sea, they will stop.

Then, after all the rivers have been calculated, it's simply a matter of going over those bits of sea, raising them up, and turning them into lakes. That gets us lakes like this:



As you can see from the second image of this region, the lake has some rivers flowing into it, but none out of it. That's exactly what we're after. In fact some experimentation reveals that this is still a flawed method - some of these lakes still have rivers going in and out where they shouldn't - but for the most part it's more or less believable, so I'll stick with it for now.

Salt lakes have a tendency to vary considerably in size depending on how much precipitation there is. In dry periods they may shrink quite a lot. The result is a tendency to be surrounded by salt pans. So let's try to implement those.

I think that salt pans - or salt flats - should be another unusual terrain feature, like the saltiness of salt lakes, that can be stored in the specials array. They also have the property of being the same elevation as the surface level of the lake, so they are very flat. At the regional level, we can calculate them immediately after the lake phase. All we have to do is go over any cells that contain salt lake and paste salt pans around them, using our trusty small lake templates. The shallower the lake at that point, the more extensive the surrounding salt pans are likely to be. As with the river valleys, doing this before the main terrain generation means that the latter will simply work around them, raising hills (if appropriate) around the salt pans.

Salt pans shouldn't appear in areas where there is too much precipitation. At the point where we're generating them, we don't yet have the regional precipitation maps. So once we do have them, we make another pass over the regional map and remove any salt pans where there's too much precipitation. So where a salt lake straddles drier and wetter climates, the salt pans will only emerge on the more arid coasts of the lake.

Here's what they look like on the relief map:


Of course, salt pans can also appear by themselves, without permanent lakes, where the water has simply dried up completely (or comes and goes sporadically depending on the weather). It would be good to put those in UW too.

Small salt pans aren't too hard to do. We can use our ever-useful small lake templates to plonk them down on random desert tiles, provided there are no rivers present. Thus the unrelenting bleakness of the desert in this picture becomes - well, very slightly bleaker:


Those teeny salt pans (in fact they're several kilometres across) add a little variety to the desert, but it would be nice to have some really big ones too. In reality the largest salt pan in the world is the Salar de Uyuni, which at about 10,500 square km would, I think, be about 50 pixels across on my maps (if it were square).

We can create larger salt pans by treating them as sort of weird lakes without any rivers or water. Basically, we can store them on the global lakes array, just like normal lakes; but on the specials array, we'll mark the same cells as being salt pans. An advantage of this is that it allows us to ensure that the salt pans are perfectly flat, even though they extend over different cells. (This also allows us to use the same system for other features we might add later, such as swamps; we would make them like lakes too, but mark them as swamps on the specials array.) Then, at the regional level, we can calculate them like lakes again, but making them salt instead of water.

That takes a fair bit of messing about, because it requires a lot of rejigging of much of the code that refers to lakes in order to make sure that it doesn't think the salt pans are actually lakes, but it gets us this:


These salt pans are created in the lake generation phase of the regional map level, i.e. before the land around them, using exactly the same methods as normal lakes; but the program then goes over them and turns them into salt flats, at the elevation of what would have been the surface level of the lake. One feature of lake generation at this point is that a modified flood fill routine is used to identity any bits of lake that aren't connected to the rest of it, and to get rid of them. I've turned that off for the salt flats, because I think it looks quite good to have a more fragmented "coastline" with odd little bits separate from the main body.

One more little tweak: adding a random chance to place small salt lakes in the middle of large salt pans:



So you get a nice effect of an old inland sea, almost entirely dried up, with just an occasional shallow pool in the vast expanse of salt. I think it helps to make the deserts just a little more interesting.

Sunday, March 10, 2019

Bits and bobs

Some small tweaks and improvements.

Varying glacial crinkliness

First, a bit more variety to the fjord routine. At the global map creation phase, the program extends mountain ranges out to sea in areas where it's cold enough for glacial action to have occurred in the past; this is meant to simulate the carving of fjords. At the moment, it extends them out by two tiles. I've changed it so that it will always extend them out by at least one tile, and the probability of extending them a further tile varies according to the roughness map. That means that some glacial coasts will be crinklier than others:




I think that makes them a little more interesting and believable.

Where did the islands go?

Way back when I was talking about global map generation, I noticed something odd. I use a flood fill technique to remove all areas of sea that aren't connected to the main ocean, and illustrated this with the following before and after images:



The flood fill did indeed remove all those annoying areas of sea - but it seems to have taken a lot of innocent islands with it! What happened?

I realised that there's some kind of confusion with the two world maps (one with mountains, one without). When the mountains/islands are made, land is placed under them on the no-mountains map, but not on the with-mountains map. The sea flood fill looks at the mountains map. So it thinks that those islands are sea, and gets rid of them.

Rectifying the problem makes the world map I'm looking at right now go from this:


to this:


Well, I had wondered at some earlier stage why not many islands were appearing, and kept upping the numbers being generated to try to force more. Now that mystery's been solved, perhaps it's time to dial back the island generation a tad...


That's a little bit more like it. Note that doing this has actually shrunk some of the continents: I'm not quite sure what's happened there, but a lot of that land must have consisted of overlapping islands and filled-in sea. Reducing the number of islands has broken them apart. (Also note that truly epic lake in the north of the largest continent - that would dwarf Lake Superior!)

It does mean we get more groups of small islands that look like this:





And I quite like those.

More natural monsoons

When describing the rain modelling, I explained that monsoons are calculated roughly. It would take forever to calculate the monsoon strength on every land cell, so the program instead calculates it for just a sample, and creates blobs of monsoon to compensate. These blobs are circles, and they can result in rather unnatural climatic patches:


They don't look great at the regional level either:


The solution to this is fairly straightforward: instead of making circular blobs, we'll just use some irregularly-shaped templates. Luckily I've already got a bunch of those - they are used for making the small lakes. All I have to do is repurpose some of that code, and this is the result:



Not perfect, but a little better at least.

Getting rid of the seam

One little routine at the end of the global terrain phase involves shifting the map left or right so that the eastern/western edges of the map come in the middle of the widest part of ocean - or, failing that, so that the minimum possible amount of land has to wrap across the edges. This generally makes the maps very nicely centred. But it's got some kind of glitch that causes the "original" edge to be visible as a vertical trench or seam on the finished map. This doesn't look good:


It's not great at the regional level either:


Close investigation of the shifting routine reveals no problems. I think it may be a flaw in the original continents generating routine, where for some reason they don't get drawn on either the left-hand edge or the right-hand edge of the map. But I can't find where that's happening, either.

The solution: another bodge. It's easy to add a routine that, after shifting the map, goes down the seam and makes each cell the average height of its neighbours to the immediate east and west. This gets rid of the sea trench, but it does still cut through the mountains:


Why is this? Because there's a stage of the global terrain generation that removes any mountains that are over sea (just to be on the safe side). Clearly that's removing mountains that are over this trench, before the map gets shifted (and the trench with it). I tried moving the shift-and-bodge to earlier in the whole global terrain creation phase - so it comes immediately after the unconnected seas are filled in, before the mountains get added to the map - and while that seemed to fill in the mountains to a certain degree, the general area just looked worse:


It's blockier around the coasts near where the seam was, and there's still something not quite right about the mountains over the seam itself. I think that something or other isn't getting properly shifted.

An alternative solution is to keep the shift-and-bodge where it was, at the end of the global terrain generation phase, but add an extra bodge to put new mountain ridges over the trench where mountains exist to the east or west. This results in the following:


Not perfect, but not totally implausible either. The trench seems to have turned into a sort of mountainous river valley. Let's just look at the river map for the region...


...and clearly something's very wrong with that river in what was the trench. It's trying to flow north and south at the same time and never reaches the sea. This must be because the shift-and-bodge occurs after the depression-filling routine, and therefore there may be depressions there, which screw up the rivers.

So, I move the shift-and-bodge to immediately before the depression-filling, and this is the result:



And that, I think, now looks OK.