Tuesday, January 26, 2021

Rain shadows in the regions

 Consider this regional map from an earlier version of Undiscovered Worlds:


There is rain coming in from the north and east of that mountain range. The mountains are stopping it, creating desert beyond - but the rain extends for some way past them, as if it hasn't quite realised it's hit the mountains.

This is caused by two things. First, precipitation at the global level was being calculated several cells at at time: every "splash" of precipitation covered an area. That meant that when precipitation fell on mountains, it would fall around them too, on both sides. Second, when the precipitation maps were smoothed, no account was taken of mountains, which meant that precipitation was effectively smeared over the map into places it shouldn't have been.

In my recent climate overhaul, both of these issues have been addressed. Global precipitation is now calculated with a much finer grain. And the smoothing routines now take mountains into account: precipitation from one cell can be averaged with precipitation from another cell only if there is a route between them that isn't blocked by mountain ranges. This means that when mountains block precipitation, they really do block it. As a result, we get regional maps like this:


Here, you can see a clear difference between the wetter land to the west of the mountains and the drier to the east, without any jarring bleed over from one side to the other. (I'm aware, by the way, that it's not tremendously realistic to have rivers flowing parallel to mountain ranges or even edging towards them like that, and doing some tinkering to prevent it is on the to-do list.) Here's what the precipitation map looks like of this region:


That shows the difference, and the sharpness of the transition, even more clearly.

Now you'll notice on that precipitation map that the mountains themselves experience higher precipitation even than the coastal strip to the west, as they should. But those areas of higher precipitation on the mountains look quite blocky. That's an inevitable consequence of the changes I made to the global precipitation model: precipitation over mountains isn't being smoothed any more, for fear of messing up the rain shadows, and so there are sharp transitions from one cell to the next. That is reflected on the regional map with these square blocks of precipitation.

When I was reworking the global precipitation, I anticipated that this would happen, and I was worried that it would look dreadful on the regional map. I was pleased to see that, although the precipitation map does display the expected blockiness, this isn't reflected in the regional map, or indeed the climate map. That's because these blocks of precipitation are over mountains, which have dramatically varying elevation, which disrupts any visual artefacts that the blocky precipitation areas might create.

But on lower mountain ranges, the effect is much more noticeable:


In this region the mountains are lower and there is only a fairly slight rain shadow, but there is still higher precipitation in the mountains, and you can see there are blocks of heavy precipitation on tiles where the mountain ridges aren't as high or extensive as those in the previous examples. As a result, the heavy precipitation is visible on the flat land around, creating those ugly green splodges. So, annoyingly, I'm going to have to do something about this.

The first step is this. As things currently stand, the precipitation in the relief map is calculated by means of a diamond-square algorithm over the whole map. This is seeded using the precipitation values in the global map for the relevant tiles. It's fairly straightforward to change things so that for any tile containing mountains, the precipitation map for that tile is instead seeded using the precipitation value that is the average of all surrounding tiles that don't contain mountains. If there are none (i.e. if this is a tile entirely surrounded by mountainous tiles), it uses the average of all of the seeds being used by its neighbouring mountainous tiles. In this way, every tile that has mountains in has its precipitation calculated as if it didn't, effectively. That means the precipitation will be lower. 

That yields this:


This is much better. There are a couple of rather annoying straight artefacts there, with the greener areas around some of the mountains in the middle, but it's much better than what we had. I'm not sure what's causing those - there isn't substantially higher rainfall there - I think that the algorithms I'm using to blend the colours in the relief maps have become a bit too sensitive to higher rainfall and are too enthusiastic about making it show greener. Some tinkering will need to be done there too.

Now we need to put the mountain precipitation back again, but only on the actual mountains themselves. For each tile where we've reduced the precipitation in the way described above, we'll assume that the wind is blowing from the neighbouring tile with the most precipitation that isn't a mountain tile. Then all we have to do is go through our tile, and wherever there's a slope going upwards in the direction that the wind is blowing, we'll increase the precipitation.

Here's the resulting precipitation map for that region:


Compare that to the elevation map for the same region:


As always, it's not perfect, but I think it's much better than what we had before.

The effect isn't as good on more substantial mountain ranges, where the precipitation looks a bit of a mess:


Here, though, the mountains themselves are craggy enough to mask all this, so the relief map looks OK:


You'll notice that there's still some bleeding of rainfall going over these mountains - some green areas to the northeast, and around that massif that extends out into the drier plains. I think this is caused by the fact that there are gaps in this range, and so the rainfall smoothing routines at the global level are allowing some tiles on one side of the range to be influenced by the rainfall in tiles on the other, as there's a clear (though not straight) path between them. Maybe that's OK. And only some ranges are having this effect - you can see on the others I've posted it's happening far less. And even more importantly, I think it's still far better than what I had to start with - compare this to the first picture up above!

Thursday, January 21, 2021

Climates again

The resizing of the world map showed up a lot of problems with the climate simulation. In particular, I found that on a larger scale, the methods I was using to track precipitation - of following lines of precipitation from the coasts inland - didn't work. They resulted in a stringy appearance. I also found that some of the climate classification calculations were incorrect, and basically all sorts of stuff was wrong. So I've taken the opportunity to do a fairly substantial overhaul of the whole system.

As always, remember that climate simulation is staggeringly complex and difficult, and my model can only hope, at best, to produce something vaguely believable. Still, I think it's an improvement. This is what I've done:

  • Rewritten the prevailing wind precipitation, so that UW tracks all of it in a single sweep rather than line-by-line. This allows the rainfall to bloom out as it moves across the land, avoiding the sometimes annoyingly straight lines between areas of high and low precipitation that we had before. It can do this across areas with no prevailing wind, too, though it loses strength as it does so.
  • Done the same thing with the monsoon precipitation. Instead of the "blobs" approach that I used before, we now have monsoons sweeping inland in great swathes. These now create proper savannahs as well.
  • Changed all precipitation to be calculated at a finer grain, ensuring that it doesn't blur across mountain ranges as it used to.
  • Made the bands of winds much wobblier, to create more variation in the latitudes at which deserts tend to appear.
  • Added more precipitation in general, particular at temperate/subtropical latitudes.
  • Reduced the amount of precipitation that falls on mountains (though not reduced the strength of rain shadows to match), ensuring that rainforest no longer appears quite so often on high ground in the middle of deserts.
  • Made temperatures more extreme as you get further from the sea.
  • Rewritten the functions that force Mediterranean climates so that they appear more naturally.
  • Added functions to force subpolar climates in roughly the appropriate latitudes.
  • Fine-tuned the temperature calculations by latitude to ensure that climates appear at the appropriate points.
  • Reworked the climate classifications to be more accurate, and ensured that the colour scheme matches the standard one.
  • Reworked the depiction of temperature and rainfall on the relief map to reflect the different climates a little more realistically.
  • Added a new colour for cold deserts on the relief map.
Most of this involved throwing in lots of magic numbers and twiddling them until things looked less bad. And most of that involved trying to get things back to how they were when I started. Still, I think the result is better than what I had before. There are still issues - my climates don't form such large, neat areas as they do in the real world; there's an annoying tendency for warm-summer humid continental areas to alternate with subpolar ones, which I can't get rid of without messing up everything else; there's too much tundra; the transition between rainforest and savannah is often too abrupt; but overall it's broadly doable. Oh and of course it's all much slower now, but it's worth it to get a more plausible final result.

So here are some global maps, in both their relief and climate versions. Climates are classified according to the Köppen-Geiger climate classification, and shown using the same colours (based on Peel, Finlayson, and Mcmahon 2007).








Now of course doing all that has messed up how precipitation is calculated at the regional level, so I need to rework that too! Yay!

Tuesday, December 29, 2020

Refining continents

I've done more tinkering to my continents. With the inland-sea-removing function reinstated, I'm getting world maps like these:



A new element in these maps is rotation. I found that some continents were coming out rather square-shaped. I did a lot of tinkering with the way in which they're generated and couldn't reliably fix this. But it occurred to me that the visual annoyance of this could be greatly reduced if I simply rotated each continent by a random amount before placing it. I think it helps - if you look at the western-most continent in that last map, it's actually quite square, but because it's been rotated, it looks OK.

Now rotating a 2D shape around a given point is not very complicated. First, I make a copy of the continent into a backup array. Then I blank the continent. Then I go through it pixel by pixel. For each pixel, I apply the formula:

newx=x*cos(angle)-y*sin(angle)

newy=y*cos(angle)+x*sin(angle)

Then we simply take the value of {newx,newy} in the backup array (which contains a copy of the original continent) and paste that into {x,y} in the continent array.

(It's slightly more complicated, because if, like me, you want it to rotate around the centre rather than around the coordinates' point of origin, you have to add and subtract the coordinates of the centre at key points, but I'll ignore that for simplicity's sake.)

Now another thought occurred to me once I'd got this working. Suppose, before plugging x and y into the above formulae, I add an offset to them. And suppose that this offset varies! That's not difficult to do. All I need to do is create yet another diamond-square fractal. Then, as I go over the continent applying the above formulae, I add an offset to x and y before plugging them into the formulae, and the size of that offset varies depending on the value of the fractal that corresponds to that point. Might this produce interesting results?


Yes! It gives us crinklier coastlines! Lots of little peninsulas and islands. We don't want to over-use this effect though, as in real life continents don't have that kind of coastline all over. So some more judicious tinkering gives us maps like these:



With an effect like this, a little goes a long way. It's hard to get the balance right, but I think these are looking pretty decent.

Now we need to do something about mountains. With the original continent method, I put down mountain ranges and created the continents around them. We're not doing that with these. We could just put down mountain ranges at random across the continents, but it would be nice to do it a bit more realistically. That means ranges in two main kinds of places: where continents overlap (like the Himalayas), and along the edges of continents (like the Andes).

The Himalaya-type mountains are fairly straightforward. We just need to identify the points where continents overlap, and then send chains of mountain ranges meandering across them:


Sometimes a larger continent is drawn entirely covering a smaller one, triggering a mountain range where one wouldn't quite expect it, but this can make for quite nice effects (this one's zoomed in a bit:


That looks to me like it could easily be a fault line between three continental plates!

Now for Andes-style mountains. Ideally, we'd be able to run a mountain range along the edge of a continent, but this would be really tricky to do. Luckily, there's nothing stopping us tinkering with the shapes of the continents at this stage. So we can choose two points at opposite sides of the continent, and then run a chain of mountains from one to the other. We'll make land under and around the mountains, and we'll also delete all other land to one side of that new land. That way, we'll effectively create a new coastline near these mountains.

Needless to say, all of that proves easier said than done, but it generates some nice results:



As always, we don't want to over-use the effect, so it's only applied to some continents.

Now we can combine both of these mountain-making methods, and also bring back a host of other effects that we had before: smaller mountain ranges scattered over the land (with some noise applied to land elevation in general), chains of islands in the sea, and most crucially, removing land by applying a fractal to the whole map. For this last move, we'll do it much more judiciously than before. Only a few, fairly small areas on the map should see significant change.

All of this gets us global maps like these:



The mountains all look much the same height with this visualisation, so the ones at continent boundaries get a bit swamped out in these images, but they're considerably more prominent on the elevation maps and should become more so when the climates are added back in.

Yes, because as you can see, I've turned off the climate simulation for the moment. This is of course partly for the sake of speed while tinkering with the global terrain generation. But it's also because increasing the map size has also shown up issues with the climate routines, so some serious amendments to those are next on the agenda.

Thursday, November 26, 2020

Continents revisited

While putting together the new UI, I've taken the opportunity to do something I'd been thinking of for a while and quadrupled the size of the global map. This obviously allows for more features and detail in each world, but it also makes the regional map a bit more realistic. If I keep the regional map exactly as it was, it means that the scale has changed: each pixel on that map now represents an area of one square kilometre. I think the features I already have on the regional map, particularly the mountain ranges, make more sense if this is the scale.

However, increasing the global map size does show up some limitations of the global terrain generation. The basic continents are made by creating long mountain ranges and sort of spreading land out from them, then adding or removing extra bits of land. However, this doesn't scale up tremendously well.


They look pretty blobby. As things stand, UW improves their appearance by creating a diamond-square fractal and then using that to remove sections of land, to create jagged coastlines:


That gives us much nicer-looking landmasses. But now that the scale has changed, they simply look too small to be proper continents. I can't just scale up this method, because using the fractal to remove land will simply fragment everything. (I don't want to use it to add land, because then I'll just end up with a fractal global map, which is unrealistic in a different way.) Consider an actual world map:


The bits I've circled in red are the areas where it resembles the areas on my maps where the fractal is used to cut away the land. It's a relatively small proportion of the world. The methods I'm using at the moment can make interesting world maps, but they can't really generate something like Africa.

So what I need is a way to create the shapes of continents that don't look like vague blobs, and are interesting and varied, but without being all jagged and broken up. Then I can combine these with the methods I already have to get maps with all different kinds of land masses, just like reality.

It occurred to me that I already had a method of generating shapes a little like this: large lakes on the regional map. There, we take a large, simple shape with lots of straight lines, and distort it into something more natural-looking. Could we use a similar technique to create continents?

Well, first we need a shape to manipulate. A fairly straightforward way of doing this is with a Voronoi diagram. Now, I said at the start that I wasn't going to use those, but while I'm not storing the actual terrain as a Voronoi diagram, I can still use a Voronoi diagram to generate shapes that I subsequently manipulate.

It's a simple thing to program, even for me, and generates this sort of thing:


That would look lovely hanging on the wall. Anyway, as it stands, this diagram has an area equivalent to the global map. What I'm going to do is use it to create the shape of a continent, which will then be pasted onto the global map, not necessarily in the same position that it occupies here. The cells of this diagram are pretty large. I can easily make them smaller, of course, by having more of them, but I really only need a rough outline for our continent.

Now I need to pick out the cells that will make up our continent. A standard way of doing this kind of thing is to use Perlin noise or something similar, but I don't want that kind of shape and in any case I don't need anything that elaborate because most of the interest of this shape will come from the Voronoi cells, as they're quite large. Just a few randomly-placed circles should be enough:



Now we just keep the Voronoi cells that that blob goes over, and that makes the basic outline of our continent. That gives us results like these:



And this is just what I wanted - they already look like very stylised continents.

So we have a basic continent shape. Now we need to disrupt its borders as we did the lakes, so it looks more natural. This will require less disruption than we did then, in fact, because we aren't trying to disguise a gridlike original shape.

It takes a lot of tinkering to get something reasonable. I try to vary many of the variables not only from one continent to another, but also within a single continent, so their coastlines don't look too uniform - there should be some smoother bits, and some more jagged bits. This gets me shapes like these:







I'm pretty pleased with these - I think they look fairly believable as continents of various shapes and sizes. The little islands that sometimes appear around them are a happy accident, the result of the fill method. When the outline of the continent is drawn, I draw a box around it, and then fill inside that box, to make a sort of negative of the continent. Then I reverse that for the final version. Since the outline can sometimes cross over itself while making especially extravagant squiggles, this can leave the insides of loops as isolated bits of land on the final shape. You'll notice there are also some squiggles of blankness inside these continents, but it's easy to remove these.

The next step is to put these onto the world map. Rather than just slap a few on at random locations, I select just one or two focal points on the world map. At each focal point, a continent will be placed. Around these central continents, other continents will be placed, either overlapping the central ones or a little way off from them. In theory, this allows us to mimic the real world map, where continents cluster in groups, with wide oceans between the groups.

The results aren't perfect, but some of them are already starting to look like potentially interesting world maps (bear in mind these are made merely by the process just described, without any removal of inland seas or shifting the map or anything):





Clearly there's still a lot of finessing to do, but I think this method has the potential to produce a good base for global maps once we add back in all the other details.

Wednesday, September 2, 2020

Change of clothes

Just a quick update!

As ever, work on this continues to inch along when I'm able. I'm focusing at the moment on redesigning the interface of Undiscovered Worlds so it looks a little more appealing and intuitively useable. I'm using Nanogui, as it's not hugely over-complex and I like the look.

This is how it's looking at the moment:


Still plenty to be done, but I think it's looking reasonable!

Friday, July 24, 2020

Quick update

Hello everyone. This is just a brief post to update the project. I've been doing lots of unglamorous bug-squashing. At long last, the lakes are *mostly* behaving themselves. Rivers are too, usually, as long as you don't look too closely. A lot of issues remain, but it's all looking a little smoother than it was, and I need to move on while I still retain some will to live. I've also done more work on the coastlines, which are never good enough, but they're looking generally pretty decent. Surprisingly, I found that my landfill method was now actually counter-productive - the coasts looked better without it. So I've removed that, presumably getting some speed increase into the bargain.

I've done some rejigging of the colours used to draw the relief maps, and I'm quite pleased with the results:








I said previously that I intended to rewrite it so that when the regional map is scrolled, it generates only the tiles on the leading edge, shifting the rest of the map rather than regenerating the whole thing each step. After several days of working on this, I've found that it is indeed faster, but it's impossible to guarantee that those tiles are exactly correct. Regenerating the entire map after it has been scrolled in this way always results in changes in those leading edge tiles, no matter what I do to get around this. The absolute bedrock first principle of the regional map is that any given cell from the global map should always yield exactly the same tile on the regional map, no matter what, so I've very reluctantly had to give up on this and keep the system of regenerating the whole regional map every time it's scrolled.

(An unexpected byproduct of this was that I discovered the little algorithm that generates the marbling effect I've added to the maps - most apparent in the sea. It doesn't mean anything but adds some nice visual interest, I think, so the work wasn't entirely wasted.)

There are still a couple of more glaring bugs to get rid of, and then it's time to think about larger global maps and larger regional maps too. Both of these will probably also require a serious rethink of the UI, which at the moment doesn't really exist.

Friday, June 12, 2020

Surprise!!!

...it's a post about lakes!

In my last post, I talked about a new way of doing rift lakes that works by drawing the outline for the whole lake in one go and then filling it, rather than by trying to make each tile by itself, as I originally did. I wanted to make better rift lakes, of course, but I was also curious to see whether this method would work at all as a possible new approach to the other kinds of lakes.

Just as a reminder: Undiscovered Worlds has four kinds of lakes. At the global level, it has (1) what I refer to feebly as "normal" large lakes, and it has (2) rift lakes. Then, at the regional level, it also has (3) what I refer to equally feebly as "normal" small lakes, and it has (4) glacial lakes.

(3) and (4) are created from scratch at the regional level, because they are relatively small and wouldn't show at the global level. (1) and (2) are much larger and are created at the global level, and must be translated into something that looks reasonable at the regional level.

(I'm ignoring salt lakes here, not to mention wetlands and ergs, because these are all treated as varieties of normal large and small lakes.)

What I'm interested in here is lakes of type (1): very large, wide lakes along the lines of the American Great Lakes. To date, my attempts to make these look reasonable at the regional level haven't been very successful. They've got even worse in the new, rewritten version of UW, with so many overlapping functions trying to correct each other's problems that I don't really understand how they work any more, and they don't look very good. The basic approach, though, remains the same: go through the lake tile by tile, create terrain using the diamond-square algorithm to expand on the terrain elevations given in the global map, and flood any areas that fall below the surface level of the lake. I want to try to replace this with a new method entirely, where we instead calculate the outline of the entire lake in one go.

The first step is straightforward: we mark out all cells that lie on the border of a tile that corresponds to lake on the global map with a tile that does not correspond to lake. That gives us this sort of thing:


(Note that some bits of rivers are still present within the lakes, but they are weird - that is fine as obviously they aren't normally calculated when the lakes are actually there. The lakes are done before the rivers, remember.)

Then, for each lake, using one border tile chosen at random in world generation as our starting point, we go around this outline and select every nth highlighted cell to be a node. To start with I'm trying n=6. If we do this and join up the nodes with straight splines, we get:


Not so different in appearance, though the corners are a little blunted because the nodes aren't in them. But because this outline is now based on the nodes, rather than simply drawn directly onto the borders between the tiles, we can shift those nodes around and hopefully make it all look a bit more natural.

I could just give a random offset to each node, but I don't think that would distort the squareness enough. Rather, I use a running offset. We go round the outline, taking each node in turn, and apply the same offset to each, altering it a little each time. That gets us this:



Already some bits are looking almost reasonable there. Now we add a bit of random variation to each node in addition to the running offset:



The nodes are being connected by straight lines here. With a bit of random curve to them, and some additional jiggling of the other parameters, we get this:


I think that's starting to look reasonable.

After this, it's basically a matter of filling it in, and also adding a few islands. These are done with templates, and I'm careful to ensure that every island is placed such that it has clear water all around it - islands can't overlap with each other or with the lake coast.

With that done, and further tweaking of the various parameters, we get lakes like these:




I think these are OK. The great virtue of this approach is that the lakes are guaranteed to be single bodies of water - there is no chance of them somehow getting split into more than one, as could happen with the old approach. That means that you can't get weird situations where the outlet river leaves a different lake from the one the inlet rivers flow into.

A disadvantage of this method is that it can't handle islands that form in the lakes at the global level - that is, where entire tiles of land exist within the boundaries of the lake. So I need to tweak the global lake creation functions to ensure that those never form. Otherwise, it's not looking too bad.

So with that, the entire functionality of the original version of Undiscovered Worlds is now in place, and refined in many ways. The next stage is sorting out all kinds of appalling bugs that are also in place. After that, some tweaks to various things, and I hope to have an initial releasable version.