Sunday, February 26, 2023

Water and sand

In my last post I talked about (yet another) new way of making coastlines better: by creating a mask for them using a simple diamond-square algorithm, and then filling in the terrain afterwards. It occurred to me that something similar could work for lakes, too.

Lakes are currently created at regional level via a horrendously complex process. Originally, I treated lakes as simply part of the regional terrain, using the diamond-square algorithm to generate the lake beds using the actual elevation values taken from the global map. This didn't work well, so I changed this to a more complicated method that traces the edge of the tiles of the lake and then disrupts it, to create a mask, and then generates new lake bed to fill it. This works fairly well most of the time. However, sometimes it goes wrong, for reasons I can't diagnose, and produces lakes with square borders or leaves them out entirely.

But it occurred to me that I could just adapt my new coastlines approach. If I'm generating a mask for the shape of the lakes before calculating the elevation of their beds, I can make that mask using the diamond-square algorithm, just as with the coastlines. The key realisation is that this algorithm doesn't have to be seeded with elevation values from the global map. It can be anything. This allows me to give it values that tend to produce good lake shapes, and then fill in the depths afterwards.

This gives results like these:


This method has several advantages over the previous one. It's much simpler and requires far less code. It also seems not to go wrong, which also helps. Moreover, this method can render lakes of any size. With the old method, for each regional map, UW would create the entirety of any lakes that were only partially on the map, as in the last image above. This meant there was a limit to how big they could be (and even the larger ones within that limit tended not to work properly). This new method doesn't do that, however. It just creates the bit of lake being shown and ignores anything outside the borders of the current region. This means we can have very large lakes. It also means that we can have very large ergs (areas of sandy desert) and salt pans, because the program treats these as weird lakes. So where before these couldn't get very extensive, we can now have immense sandy deserts like this one:


Indeed there's nothing to stop us now from having Arrakis-style planets with ocean-sized deserts of sand. As with everything, we don't want that to happen too often, but anything that (believably) increases the range of possibilities is good. Some more adjustments to this new system are needed, but it seems to be fairly robust so far, so I'm quite pleased with it.

Tuesday, February 7, 2023

Sinking the extra islands

In my last post I mentioned an issue with excessive islands appearing around coastlines. Happily, it's proven to be a very easy problem to fix (at least I think so...), but I thought it worth explaining.

Here's an example of the problem:

In itself there's nothing wrong with this, but it's a problem when all coastlines look like this - and as you can see in the last post, they do. But why? If you look through earlier posts on this blog you'll see mostly much less busy coasts. Somewhere along the line, I've made some kind of change to tackle some other problem, and it's had the unexpected side effect of replicating the Hebrides everywhere. Which is fine on occasion, but we don't want it everywhere. It's another illustration of the difficulty of making changes to what is now such a complicated piece of code, as it has so many moving parts that a small tweak in one place can have unlooked-for ramifications elsewhere.

How are coastlines made, anyway? Well, the terrain at the regional level is basically done by seeding the corners of the tiles with values taken from the corresponding cells at the global level, and then applying the diamond-square algorithm to fill in all the rest. Where terrain higher than sea level meets terrain that's lower, we get coasts. There are then endless tweaks to make them look better, but the diamond-square is at the heart of the process.

I think that what's happened has something to do with the changes I made a while ago to the sea bed, especially the addition of continental shelves. This means shallower seas near the coasts on the global map. Shallower seas mean more islands on the regional map, because the diamond-algorithm basically makes the terrain bumpy, and if the terrain is near the surface of the water to start with, lots of those bumps will stick out of it. (This is especially so given that the algorithm is set to tend to bump land up, in order to emphasise river valleys.) The solution, then, is simple. I add to this diamond-square algorithm a check to see whether a point at the corners or on the side of the tile is below sea level. If it is, we make it a lot lower. As a result, the algorithm tends to produce lower land around the sea, and far fewer islands are produced.

But doesn't this result in undesirably deep seas around the coasts? No, because the undersea terrain that this algorithm produces isn't actually used for the final map. Instead, there's another diamond-square-based function that creates undersea terrain. UW calls the first function first, and works out what's land and what's sea, and the heightmap for the land. It then calls another function to create seabed, and then pastes that onto the sea regions of the original heightmap. This allows me to make changes to the land terrain generation without messing up the seabed, and vice versa. So in this case, we can artificially lower the seabed in the way described above during the initial terrain generation, and it won't affect the final seabed - but it will affect the coastlines.

Here's what the above map looks like after doing this:


This looks much more plausible. Some islands still remain, and of course we don't want to get rid of them entirely. I've set it so that the island-reducing tweak varies in strength. It's weaker in areas that have higher roughness, and much weaker in arctic-type areas where one might expect fjords. So crinkly little islands are more likely in such areas. As always, variety helps to make the maps more believable, at least in theory.

(Also, notice how in the first picture there is one river that doesn't reach the coast. I think this is because the land has been extended out into tiles that correspond to ocean cells on the global map, and the river simply doesn't reach that far. There are functions that are supposed to deal with such cases by extending the rivers out to the coast if need be, but they seem to have failed here. In any case, you can see in the second picture that the coast has retreated inland and the river now reaches the sea properly, so that's a bonus from this tweak.)

Sunday, February 5, 2023

Mud and sand

Having grown up by the coast, I'm very aware of the need for a terrain generator to be able to handle different kinds of coastlines. So I wanted to try to include some in Undiscovered Worlds.

Since I currently live near the Bristol Channel I'm particularly aware of the importance of mud flats, so I had a go at incorporating those first. The basic idea depends on a feature that has been present in UW for a long time: inlets. The program removes land around river mouths, depending on factors such as the size of the river and the tidal range at that point. It occurred to me that it's easy to keep track of where these inlets have been created, and we can simply lay down mud flats around them - again based on factors such as the size of the river and the tidal range. Mud flats, of course, are represented by an array of bools within the region object.

At this point things got very complicated as I decided this would only make sense if we also kept track of how much silt every river is transporting. I wrote a new system to simulate this and got it mostly working, but annoyingly it wasn't quite right. This was a pain as the maps looked quite good with river colours varying from bright blue to dull mud, depending on their silt content, but the fact that sometimes this didn't work right (with small stretches of river inexplicably showing too much or too little silt) made it not really worth the effort - especially as it was largely a visual effect that didn't really make much difference to the world generation.

So after scrapping all that, I went back to the inlets. In this map, inlets are marked in magenta:


These are all river mouths where the program has cut away land to make it look like the rivers have eroded the coastline. Most are for very small rivers, but some are for larger ones.

Now we create a temporary array to hold silt levels. Going through the map tile by tile, we lay down silt levels on coastal cells that are within inlets. The levels of silt are determined by the size of the river and the tidal strength of the area. Then, we go through the map again and spread the silt out from these points, both inland and into the sea. Any cells that have a certain level of silt or higher are then turned into mud flats, which also involves setting their height to 1m above sea level, and possibly creating some saltwater wetlands nearby too.

Only a few inlets actually have enough tidal strength to generate mud flats big enough to show on the map - bearing in mind that each pixel is a kilometre, so the mud flats have to be quite extensive to show up. Here is a region that has quite a lot of them:


And on the relief map, they blend in fairly subtly with the wetlands around them:



We can also add mud flats to river deltas, too:

Now we want nicer beaches too! Namely, sandy beaches and also shingle ones. We can make these in exactly the same way. With the beaches, though, the tidal range is more important than river size, so we tend to get mud flats around large rivers and sand or shingle around small ones. And where mud flats tend to spread inland along the rivers, beaches tend to spread along the coast. Finally, we set it so that mud, sand, and shingle can all mix with each other, making for varied coastlines.

The resulting effect is quite subtle, because again only really large beaches can be seen at this scale. Here, you can see a few spots of yellow or brown along the coast where there is enough sand or shingle to make a large beach:


There might not seem much point adding such minor features, but one of the new planetary variables is lunar gravity. Worlds with weak lunar gravity have small tidal variation, and relatively few mud flats and beaches. But worlds with strong lunar gravity can have extreme tides, with correspondingly extensive beaches and mud flats:

There are a couple more tweaks we can add. First, mud flats get a chance to generate barrier islands along the ocean-facing edge. This results in areas like the Wadden Sea, where a string of islands protects a large intertidal zone. Second, in tropical areas, mud flats (and salty/briny wetlands) get mangrove forests on them. You can see the darker green coastal areas here (the user can turn off this effect if desired):


So that's that for coastal zones, at least for now. The next job is to try to work out why all my coastlines have acquired far too many little craggy islands and get rid of most of them (they never used to look like that!). After that, I'll aim to release the updated version.

Monday, January 9, 2023

Warp speed

I liked the effect of domain warping at the global level, and I wondered: might it help at the regional level too? With the regional terrain, there's a constant danger of the underlying tile pattern becoming apparent and making the terrain look like a grid. So I'm always looking for ways to disrupt this.

Originally, I intended every tile at regional level to be calculated entirely independently of the others, so that the whole map could be scrolled tile-by-tile while keeping every feature the same. I eventually gave up on that. Now, although many features are created on a tile-by-tile basis, many bleed across into their neighbours. You can't scroll tile-by-tile now: each regional area always has the same 32x32 tiles in it. So I thought: suppose I were to apply domain warping to an entire regional area. Might that make it less grid-like?

One complication is that the warping needs to be faded away towards the edges of the region, so that it joins up neatly to neighbouring regions. This wasn't hard to do. I then spent a great deal of time tinkering with various ways of doing it. One problem was that rivers can't be warped in this way. Or rather, they can, but they look terrible. I did find that warping the mountains worked well to make them a bit less gridlike - but for this to work, I had to warp the normal terrain too, because otherwise the mountains might move away from the higher normal terrain that normally lies beneath them. Since I wasn't moving the rivers, warping the terrain around them did leave some rivers travelling over what were effectively aqueducts if the land around them was lowered. I tried making it so that warping is only done if it would raise the land in question. This solved the river problem, but now the high terrain under and around mountains tended to get stretched across the landscape, creating broad plateaux, which looked weird. (There could also be a similar effect near the edges of the map if the natural variation in warp synced with the reduction in warp strength at the borders, creating stretch marks.) The only way to get around this that I could find was to reduce the strength of the warp effect, but doing this enough to overcome that problem meant that it had little overall impact.

So eventually I gave up on warping the terrain on land. However, I did find a similar effect worked well on the rifts and ridges on the sea floor. Because these feature a lot of parallel ridges, they can look a  bit like they've been drawn with a ruler. But a bit of warping really helped here, since there are no rivers or anything to get in the way. Rather than simply warp the whole undersea terrain after the ridges have been drawn, I generated the terrain normally but warped the coordinates that the ridges would be drawn to, and then drew them to those coordinates. This meant that the ridges themselves don't look stretched, but they are forced away from the underlying tile structure.

Compare this before shot:


...to this after one:


It's a shame I couldn't get this to work equally well on land, despite all that tinkering, but I think this is still a nice improvement, minor though it is.

Tuesday, December 13, 2022

Craters

I've made some more refinements to my non-terran worlds. One is that multiple world terrains can now  be blended into a single world map, making for more variety within worlds. Another is the incorporation of variations on the warped fractals I've been using so far. Warped voronoi maps can (rarely) appear, and so too can the extreme kind of warped terrain that ThingOnItsOwn rather charmingly calls Monstrous Terrain. This can produce interestingly weird terrain like these:


But these worlds still look a bit dull at the regional level, because they have no proper hills or mountains. They only have the up-and-down of the basic underlying terrain, and no matter how dramatic that may be at the global scale it generally comes out looking very gentle and gradual at the regional scale. So we want some features for these worlds that will look interesting at all scales.

An obvious kind of feature for alien worlds is craters. But how to do them?

Here is my thinking. A crater is basically a big circle. Suppose we put a lot of circles at random onto the map. Each one is a flat depression. However, craters also feature a raised rim, and usually a peak in the centre. We can represent these in a similar way to mountains - an extra array, which we use to draw them directly onto the regional map. At the global level, we use that array to display the rims as raised, although the actual heightmap is not that high. As with normal mountains, rivers and the depression-filling algorithm will ignore the central peaks and the rims, as they're not part of the normal base terrain.

That gives us this:

Well, it's a start. But of course craters aren't really perfectly flat. The terrain should slope downwards from the rim towards the centre. Adding this in gives us this:

These are looking better, but they're mostly too big, and too evenly distributed. So I introduce a global fractal to determine their distribution, and also create additional rules: on some worlds they appear only above a certain elevation, on some only below a certain elevation, and on some only where the land slopes steeply. Also I make it so that craters don't raise land that's below them. This gives us maps like this:


I think this is starting to look pretty good! As you can see, some craters are low enough to create small circular seas. These look quite good, but I don't think we always want them, so I add an extra pass of the small-sea-removing function after doing the craters for most worlds.

One problem, though, is that most craters are depressions. If there isn't water in them, then that will mess up rivers. We can solve that by running our depression-removing algorithm again, but that will fill up most of our nice new craters. My solution is to create yet another global fractal and then use that to blend the new, cratered terrain with the original, uncratered terrain. This makes the craters imperfect, with lower areas in their rims, so the depressions can be filled without the craters being filled right up. If there's no sea in the world, then we don't bother with any of this, as there won't be rivers.

There's one other adjustment to make. In reality, any craters on the surface of a planet with life will have mostly eroded away, because a planet with life must (a) have a reasonably thick atmosphere and (b) not have been subject to frequent bombardment from space for a long time. In drier regions, craters may still be seen, like the famously misnamed Meteor Crater, but in wetter ones they will get eroded away. This is unlike mountains formed by tectonic action, because while those also get eroded away, they're constantly being raised up at the same time, which balances the effect.

So in the climate simulation, I give rainfall the ability to lower the "mountains" around the rims of craters.

That gives us craters on the global map. How do we deal with them on the regional map? The basic idea is to add in the central peak and the rim of each crater much as mountains are done. So we paste peaks in the centre of each crater and in a circle around the rim. As with normal mountains, we leave gaps where any rivers might be passing through. 

This gives us an effect like this:


I think this looks pretty decent. As you can see here, craters are drawn overlapping each other, with the rims of "earlier" craters being overwritten by the floors of "later" ones. The crater in the centre is partial to begin with because the elevation drops to the northwest, so the land there is lower than the floor of the crater would be.

An extra detail to make things a little more interesting is to have "arms" of peaks radiating out from the craters, like these:





And I think that's that for craters. Hopefully these should make the alien planets a little more interesting, and of course we can add a few of them to some of our Earth-like planets too, just to shake things up a bit.

Thursday, November 17, 2022

Weird worlds

Suppose we want a planet that looks something like what Mars might look like if it had water and life. Such a world has no tectonic activity, so there are no continental plates and no mountain ranges like there are on Earth. How do we make interesting terrain?

The obvious place to begin is with the trusty diamond-square algorithm, which, like the more widely-used Perlin Noise, can give us a randomised height map of this kind:


Stick in some sea below a certain elevation and we get this:


We've seen maps of this kind plenty of times already, of course, and we've also seen why they're not really suitable for world maps. There isn't proper structure to them - land and sea (and different elevations in general) are spread more or less evenly throughout the world.

Well, in fact that's not completely true - you can see on the map above that there's an area of ocean just left of centre - and this is because my diamond-square fractals are rather more complicated than usual. The parameters by which the elevation may be changed vary throughout the map, giving it a bit more variety than you would usually find in such images. If we increase this effect, we get areas where the image is more blurry:


That adds some variety, but it doesn't really make for a realistic map. Luckily there are more techniques at our disposal. One of the simplest but most effective is domain warping. I used this previously in Undiscovered Worlds to create noise at the local level, but subsequently got rid of it in favour of a more effective method for that purpose. But now let's bring it back! Briefly, we create three fractals: one as the source image, one to represent X-axis warping, and one to represent Y-axis warping. Each point on the map is then taken from the corresponding point on the source image, but displaced according to the other two fractals. We can easily control the strength of the warp by multiplying the two warp fractals by a constant.

Applying this to the last fractal shown above, with strength=20, we get this:


Strength=40:


And strength=80:


This is starting to look pleasingly weird! Note in particular how this technique creates ridges and valleys as it pulls the image about. This could make for interestingly alien-looking terrain.

We can also do another warp on it after the first is finished. Here's what happens if we do a warp of strength=80 and then another one of strength=60:


Even weirder! This effect is probably best used at relatively low strength, but by varying both this and the original warp we can get a variety of interesting terrain that doesn't look like the same old noise.

Another technique is to exaggerate the difference between peaks and valleys. If we read the elevation as varying between 0.0 and 1.0, and simply multiply each point's elevation by itself, we can do this easily. This effectively lowers all of the elevations, but the lower an elevation is to start with, the more it is lowered, causing slopes to be exaggerated. If we do this to the 80-strength single-warped image, we get this:


There's one more step we can take, which is to create a fractal with a very low level of detail, like this:


We can then multiply everything in the terrain by a fractal like this, thus forcing the appearance of large-scale areas of relatively high or relatively low elevation. Not only that, but we can use a similar technique on all of the effects we've tried, to vary their strength throughout the map. That can give more variation across the world. Here's the end result:

Here's part of it enlarged, so you can see the gnarliness in more detail:

I think that's a decent start for an alien-style terrain without too much effort.

One other thing needs to be considered, and that's the ocean. Using a mask to reduce some parts of the map, and also squaring the elevations to get more sharply defined peaks, tend to produce maps that are mostly sea. There's nothing wrong with that in itself, of course, and it's what we'd want if we were making Earthlike maps, but with these ones we don't want them all to be like that. So we'll lower the sea level by random amounts as well. That means we can get worlds with smaller seas, or that are mostly land, like Titan.

For our Earthlike worlds, we use a simple flood fill routine to identify the largest body of water in the map and then turn any separate bodies into land, because we want to have a single ocean. But this wouldn't be appropriate for these more alien worlds with less water, where there could easily be multiple separate seas. However, we don't want really small seas, which will always form when you declare any point on a fractal that's below a certain elevation to be water - as you can see in the last image above, in fact. That does seem unrealistic, and too obviously caused by over-reliance on fractals. So we do want to remove seas that are below a certain size, without necessarily having just a single ocean.

We can randomise what the size threshold is, for different worlds. One side effect of this is that if the size threshold is large, the algorithm may remove all sea altogether, resulting in large expanses of mostly flat plains that contrast with the high land from the fractals. I think this gives a nicely lunar sort of effect:

So what happens if we turn the climates back on? I had to do yet more work on the climate model to allow it to handle worlds without any sea. Briefly, some rain can still fall on such worlds, though not much, and mostly where the land slopes; again, think of Titan, which has no oceans - only methane lakes covering a relatively small proportion of its surface - but which does have methane rain and even rivers flowing into its lakes.

With the climate turned back on, we can get some interesting results. For one thing, the large areas of high land that this new generation method creates tend to lead to extensive snowy regions even in equatorial latitudes (on normal temperature settings). Consider this medium-sized world:

Here, an immense system of linked lowland plains winds around and between areas of towering highlands. The relief map looks like this:

The highlands are uniformly frozen, even though this world has an average temperature only 3°C lower than Earth's, while the lowlands - which are still fairly highly elevated - are frozen in the higher latitudes but warmer elsewhere. Most of this world that isn't frozen or tundra is either hot or cold desert, as you can see from the climate map:


But pockets of rainfall exist, mostly around the steep transitions between highlands and lowlands (even enough for some small patches of rainforest). As result, there are rivers, which flow into a number of saltwater lakes:


If you compare the rivers map with the elevation or relief maps, you'll see that some of these rivers are winding their way a tremendously long distance through the lowland system before ending in a lake (or disappearing off the top or bottom of the map, which is allowable in normal worlds but looks rather weird here, so that will need to be dealt with). Despite their length, the arid nature of the world means these rivers are only modest in size. Here are a couple of the larger salt lakes, near where a series of cliffs leads up to the frozen highlands:

And here is a patch of rainforest along the edge of another part of the highlands:

As is probably evident, I think this is a pretty interesting world. It's very different from the Earthlike worlds that UW has been generating to date, but it's not simply a map of random noise either. It's a plausible-seeming alien planet with meaningful large-scale geographical features, and one can imagine the kinds of civilisations that might exist in these strange conditions.

However, the complete lack of hills and mountains does mean that the regional maps look pretty uniform much of the time. Although the landscapes are weird, they look a bit bland compared to others that UW can produce, and there are even some dreaded grid artefacts making themselves known. So we need to think about what new kinds of smaller-scale features might be found on worlds of this kind, and how to make the regional maps look a little more interesting.

Monday, November 14, 2022

Variations

I've always planned Undiscovered Worlds to be not simply a map generator but a world generator, with - ideally - a quasi-realistic sci-fi sort of feel. At the moment it's creating maps of what are effectively alternate Earths. But I'd like to create more variety in the kinds of worlds it can create maps of.

To some extent this has already happened. When I rewrote the continent creating functions, I didn't delete the original ones. They're still in there as a possible variation, so while most worlds use the newer version, a few will still use the original. The original's not as good, but it's worth keeping for the sake of variety.

So in that spirit I've been working on expanding the range of possible worlds that UW can create.

First, worlds of different sizes are now possible. In addition to the roughly Earth-sized worlds that already exist, you can have worlds with a quarter of the surface area (roughly Mars-sized) and worlds with a sixteenth of the surface area (roughly Moon-sized). (Other sizes aren't really possible thanks to the limitations of the diamond-square technique, which I use extensively.)

With worlds of varying sizes come variations in gravity too. In fact gravity can now be anything from 0.05g to 10g. On low-gravity worlds, mountains are taller and wider, while river valleys are wider but shallower:


On high-gravity worlds, by contrast, mountains are small and river valleys are narrow but deep:


In addition to size and gravity, there are several new variables, which mostly affect the climate in various ways:


I've extensively rewritten the climate simulation (again), which really ranks up there with lakes as one of the most gruelling elements of this whole thing. The problem with climates is that there are so very many moving parts that any changes to one element can have knock-on effects with all sorts of other things. This time, I had to rewrite it so that it could handle (with sufficient plausibility, if not real accuracy) not only Earthlike conditions but a huge range of other possibilities as well. Still, I think it worked out just about OK.

The simulation can now handle quite dramatically different circumstances, which can be caused by variations in the planet's orbit. Obliquity, for example, refers to how tilted the planet's rotation is compared to the plane of its orbit around the sun. Earth's is roughly 22.5 degrees, and this is what causes our seasons, as different parts of the planet are angled towards the sun at different times of year. Relatively modest changes to obliquity can yield dramatic results. At low obliquity, there is little or no seasonal change throughout the year, which means no continental climates or subpolar regions, and you tend to get lots of rainforest, deserts, and temperate oceanic regions. At higher obliquity, the seasons get more and more dramatic. Not only that, but as the obliquity gets higher the poles get hotter, because they are spending more of their time pointing towards the sun. At the highest obliquities, the poles are actually hotter on average than the equator, though they experience huge shifts in temperature throughout the year. The equator, meanwhile, has two summers and two winters in every year.

Here's a world with high obliquity, showing permanent sea ice at the equator but not the poles!


Eccentricity, meanwhile, is how elliptical the planet's orbit is around the sun. Low eccentricity means a roughly circular orbit, while high eccentricity means a highly elliptical one like a comet. Earth has an extremely low eccentricity, which means that it is roughly the same distance from the sun all the time. But a planet with a high eccentricity would experience hotter temperatures for part of the year, as it comes close to the sun, and then colder temperatures as it swings away. Moreover, because planets in such orbits move more quickly the closer they are to the sun, the hotter part of the year would be shorter than the colder part, with this effect being more noticeable at higher eccentricities. So with high eccentricities, you get global "seasons" - but the "summer" is shorter than the "winter". To make things more confusing, the "seasonal" difference is greater at the equator than at the poles, rather than the other way around as with seasons caused by obliquity.

Things get really confusing if you raise the eccentricity and the obliquity. Depending on how high you set them, you get a world with seasons similar to our own but where one hemisphere has a short, hot summer and a long, cold winter, while the other has a short, mild winter and a long, mild summer (Mars experiences something like this, to a moderate degree). Here's a world like that:


Finally, all of these new variables are controllable by the user as well. It's now possible to create custom worlds where you specify the size of the world, the approximate proportions of land and sea, and the variables shown above. So you can create worlds with really exotic climates if you want to, or specify worlds with exactly the same variables as Earth or only slightly different, or have an ice-bound moon with an ocean below the surface.

There are still some wrinkles to iron out with all of this, and then the next plan is to create some new terrain types that might be appropriate for worlds that don't resemble Earth so closely.